<?/*
	// File:	functions.inc.php
	// Purpose:	web-cp Interface functions (API)
	// Author:	Felix <webmaster@can-host.com>
	*/

// Use hook/module code
$tmp = 'hook.inc.phps';
include($tmp);

//defines
define('USER_LEVEL_ROOT', 0);
define('USER_LEVEL_SERVER', 1);
define('USER_LEVEL_RESELLER', 2);
define('USER_LEVEL_DOMAIN', 3);
define('USER_LEVEL_USER', 4);

///////////////////////////////////////////////////////
// Provide Request headers for debugging irregardless
// of webserver in use
function request_headers(){
    if(function_exists("apache_request_headers")) // If apache_request_headers() exists...
    {
        if($headers = apache_request_headers()) // And works...
        {
            return $headers; // Use it
        }
    }

    $headers = array();

    foreach(array_keys($_SERVER) as $skey)
    {
        if(substr($skey, 0, 5) == "HTTP_")
        {
            $headername = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($skey, 0, 5)))));
            $headers[$headername] = $_SERVER[$skey];
        }
    }
    foreach(array_keys($_REQUEST) as $skey)
    {
        if(substr($skey, 0, 5) == "HTTP_")
        {
            $headername = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($skey, 0, 5)))));
            $headers[$headername] = $_REQUEST[$skey];
        }
    }

    return $headers;
}



///////////////////////////////////////////////////////
// Start Webalizer Functions
//retrieves webalizer file, either .html or .png
function webalizer_get_file($file){
  global $domaindata, $cfg;
  if (!isset($domaindata['domain']) && isset($_REQUEST['domain']))
    $usedomain = $_REQUEST['domain'];
  else
    $usedomain = $domaindata['domain'];
  if (isset($_REQUEST['host']))
    $usehost = $_REQUEST['host'];
  else
    $usehost = $domaindata['host'];
  if (!isset($cfg['webdir'])) $cfg['webdir'] = '/home';
  $webalizerfile = $cfg['webdir'].'/'.$usedomain.'/'.$usehost.'/stats/'.$file;
//  echo $webalizerfile;
  if (file_exists($webalizerfile))
    return file_get_contents($webalizerfile);
  else
    return "File not found.";
}

//alters links, .html
function webalizer_change_links($current_url, $subject, $type) {
  if (isset($_REQUEST['host']))
    $usehost = "&host=".$_REQUEST['host'];
  else
    $usehost = "";
  return preg_replace("/($type=\")(?!http)(.*?)\"/is","$1$current_url".$usehost."&webalizerfile=$2\"",$subject);
}

//alters links, .png
function webalizer_change_png($subject, $type) {
  global $domaindata;
  if (isset($_REQUEST['host']))
    $usehost = $_REQUEST['host'];
  else
    $usehost = $domaindata['host'];
  return preg_replace("/($type=\")(?!http)(.*?)\"/is","$1domain/includestat.php?domain=".$domaindata['domain']."&host=".$usehost."&webalizerfile=$2\"",$subject);
}

//sanitise html and body tags
function webalizer_sanitise_html($stats) {
	if (($startpos = stripos($stats, '<body')) && ($startpos = strpos($stats, '>', $startpos)) && ($endpos = stripos($stats, '</body>', $startpos))) {
		return substr($stats, ++$startpos, $endpos - $startpos);
	}
	return $stats;
}
/////////////////////////////////////
// End Webalizer Functions

// assign common filemanager login code to a function
function filemanager_login($personaldata) {
	global $cfg, $T;

	// Obtain real username
	$uniquedata['username'] = $personaldata['username'];
	$uniquedata['id'] = $personaldata['id'];
	call_hook('user:get:username', $uniquedata);
	$unique = $uniquedata['username'];

	if (version_compare(phpversion(), '4.2', '<'))
		$FTPid = @ftp_connect($cfg['ftpsysname']);
	else {
		if (!$FTPid = @ftp_connect($cfg['ftpsysname'], $cfg['ftpsysport'], 8)) {
			sleep(2);
			$FTPid = @ftp_connect($cfg['ftpsysname'], $cfg['ftpsysport'], 16);
		}
	}

	if (!$FTPid) {
		echo '<p>'.$T['FTP Connect Error'].$cfg['ftpsysname'].':'.$cfg['ftpsysport'].'</p>';
		@ftp_quit($FTPid);
	} else {
		$login_result = @ftp_login($FTPid, $unique, $personaldata['password']);
		if (!$login_result) {
			echo '<p>'.$T['FTP Login Error'].'!</p>';
			@ftp_quit($FTPid);
		} else {
			return $FTPid;
		}
	}
}

function verify_access_level($userlevel, $required, $edit_all=true) {
	return $userlevel <= $required-($edit_all?1:0);
}

// use or emulate posix_getpwnam based on cfg settings
function webcp_getpwnam($username) {
	global $cfg;

	if ($cfg['use_posix_getpwnam']) {
		$ret = posix_getpwnam($username);
	} else {
		// Get uid and gid information
		exec('id '.$username, $idresult);
		$tmpstr = preg_replace('/\([^ ]*\)/', '', $idresult[0]);
		$tmpstr = explode(' ', $tmpstr);
		foreach($tmpstr as $str) {
			$strarray = explode('=', $str);
			$ret[$strarray[0]] = $strarray[1];
		}
	}
	return $ret;
}

// detect the user's preferred language
function detect_user_language() {
	global $cfg;

	// Get an array of language abbreviations and their q-values
	$tmplangArray = explode(',', $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
	foreach($tmplangArray as $val) {
		$langQArray = explode(';', $val);
		if (sizeOf($langQArray) == 2) {
			$Qval = str_replace('q=', '', $langQArray[1]);
		} else {
			$Qval = 1;
		}
		$langArray[$langQArray[0]] = $Qval;
	}
	arsort($langArray);

	// Set up our association between abbreviations and languages
	$langComparison = Array('da' => 'danish', 'en' => 'english', 'fr' => 'french', 'de' => 'german', 'it' => 'italian', 'no' => 'norwegian', 'pt' => 'portuguese', 'ru' => 'russian', 'es' => 'spanish', 'sv' => 'swedish');

	// Determine available langauges via cfg
	$cfgLangs = explode(',', $cfg['lang']);

	// Determine our intersection of available langauges (cfg) with known language abbreviations
	$availableLangs = array_intersect($langComparison, $cfgLangs);

	// Determine intersection of requested languages and available languages
	$usefulLangs = array_intersect_key($langArray, $availableLangs);

	// Find the best language that matches and return it
	foreach($usefulLangs as $key => $val) {
		$lang = $langComparison[$key];
		if (file_exists("lang/".$langComparison[$key].".phps")) {
			return $lang;
		}
	}
	return false;
}

// load global arrays
function load_globals() {
	if (!isset($_SERVER)) {
		global $_SERVER, $_GET, $_POST, $_ENV, $_SERVER, $_COOKIE, $_REQUEST, $_FILES, $_SESSION;
		$_GET    = &$HTTP_GET_VARS;
		$_POST    = &$HTTP_POST_VARS;
		$_ENV    = &$HTTP_ENV_VARS;
		$_SERVER  = &$HTTP_SERVER_VARS;
		$_COOKIE  = &$HTTP_COOKIE_VARS;
		$_REQUEST = array_merge($_GET, $_POST, $_COOKIE);
		$_FILES = &$HTTP_POST_FILES;
		$_SESSION = &$HTTP_SESSION_VARS;
	}
}

// generate a seal based on the data, time and secret key
function make_seal($data) {
	global $cfg;
	$time = time();
	$salt = mt_rand();
	$hash = md5($time.$data.$salt.$cfg['key']);
	$seal = pack('LLH32', $time, $salt, $hash);
	return base64_encode($seal);
}

//verify if the  previously generated seal is valid
function verify_seal($seal, $data) {
	global $cfg;
	$seal = base64_decode($seal);
	$val = unpack('Ltime/Lsalt/H32hash', $seal);

	if(!$val || $val['time']+60*5 < time()
	   || md5($val['time'].$data.$val['salt'].$cfg['key']) != $val['hash'])
		return false;

	return true;
}

// Generates a random string of $length length
function make_salt($length=8) {
	make_seed();
	$char_list = '0123456789'
		.'abcdefghijklmnopqrstuvwxyz'
		.'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
		.'+-' //base64
		//'@^&/.'
		;
	$salt = '';
	for($i=0; $i<$length; $i++) {
		$rand = mt_rand(0, strlen($char_list) - 1);
		$salt .= $char_list[$rand];
	}
	return $salt;
}

// Generate a sendfile.php URL from $data
function sendfile_url($data) {
	if(empty($data['filelocation']))
		return false;

	if(empty($data['filetype']))
		$data['filetype'] = 'application/octet-stream';

	if(empty($data['filename']))
		$data['filename'] = basename($data['filelocation']);

	if(isset($data['removefile'])) {
		if(empty($data['removefile']) || !(bool)$data['removefile'])
			$data['removefile'] = 'false';
		else
			$data['removefile'] = 'true';
	}

	return 'sendfile.php?data[filetype]='.$data['filetype'].'&data[filename]='.$data['filename']
	      .'&data[removefile]='.$data['removefile'].'&data[filelocation]='.$data['filelocation']
		  .'&data[seal]='.make_seal($data['filelocation']);
}

// seed the random number generator only once
function make_seed() {
	static $randomized=false;
	// php/4.2.0+ seeds itself
	if (!$randomized && version_compare(phpversion(), "4.2.0", "<")) {
		list($usec, $sec) = explode(' ', microtime());
		$init = (int) $sec + (int)($sec * $usec);
		$init .= @getmypid();
		$seed = hexdec(substr(md5($init), -8)) & 0x7fffffff;
		mt_srand($seed);
		$randomized = true;
	}
}

// Function:	webcp_log()
// Utility:	Centralize all web-cp fatal errors, warnings, logging
// Usage:	webcp_log(ERROR_LEVEL,ID,EXTRA,LOG_MSG,REMOTE_IP,ECHO = 0)
// Examples:	webcp_log(1,$data['id'],$data['username'],"login failed",$_SERVER['REMOTE_ADDR']);
//		webcp_log(2,$userdata['id'],$host.".".$domain,"domain modify",$_SERVER['REMOTE_ADDR']);
// Definitions:	ERROR_LEVEL:	0: fatal  1: warning  2: logging 3: screen output only
//		ID:		User or domain id that generated the function call
//		EXTRA:		Extra usefull info about ^^
//		LOG_MSG:	Error/Message to log
//		REMOTE_IP:	Remote address or local name that triggered the function call
//		ECHO:		1 to echo, 0 to log only (optional, 0 by default)
//		$cfg['loglevel'] : 0 for none, 1 for fatal errors, 2 for +warning, 3 for +activity logging
function webcp_log($level, $id, $extra, $log_msg, $remote_ip, $echo = 0) {
	// Get Configurations
	GLOBAL $cfg;

	if (is_array($log_msg)) {
		ob_start();
		print_r($log_msg);
		$log_msg = ob_get_contents();
		ob_end_clean();
	}

	if ($echo) {
		if (php_sapi_name() == 'cli') {
			if ($level <= $cfg['cliloglevel']) {
				fwrite(STDERR,"($extra) $log_msg\n");
				fflush(STDERR);
			} else {
				fwrite(STDOUT,"$log_msg\n");
				fflush(STDOUT);
			}
		}
		else {
			if ($level <= $cfg['cliloglevel'])
				echo "($extra) $log_msg\n";
			else
				echo "$log_msg\n";

			flush();
		}
	}
	// DB log
	if ($level <= $cfg['dbloglevel']) {
		$SQL = "INSERT INTO log SET error_level='".$level."', id='".$id."', extra='".$extra."', log_msg='".$log_msg."', remote_ip='".$remote_ip."'";
		mysql_query($SQL);
	}
	// file system log
	if ($level <= $cfg['fileloglevel']) {
		// open file as r/w & point at the end of the file
		$logfile=fopen($cfg['logfile'], 'a+');
		fwrite($logfile,$level."|".$id."|".$extra."|".$log_msg."|".$remote_ip."|".date("YmdHis")."\n");
		// close file
		fclose ($logfile);
	}

	// mail log
	if ($level <= $cfg['mailloglevel']) {
		mail($cfg['adminmail'], 'web-cp log entry', $level."|".$id."|".$extra."|".$log_msg."|".$remote_ip."|".date("YmdHis"));
	}
}

// Load input variables
function load_input_vars($inputvarname, $allowpost = 1, $allowget = 1, $cleanInput = 1, $allowedTags = '') {
	if (isset($_SERVER[$inputvarname])) {
		$var = $_SERVER[$inputvarname];
	} elseif (isset($_REQUEST[$inputvarname])) {
	  	if (isset($_POST[$inputvarname]) && $allowpost) {
	  		safe_trim($_POST[$inputvarname]);
	  		if ($cleanInput) {
				clean_input_vars($_POST[$inputvarname], '', $allowedTags);
			}
			$var = $_POST[$inputvarname];
		}elseif (isset($_GET[$inputvarname]) && $allowget) {
			safe_trim($_GET[$inputvarname]);
			if ($cleanInput) {
				clean_input_vars($_GET[$inputvarname], '', $allowedTags);
			}
			$var = $_GET[$inputvarname];
		}
	}
	if (isset($var)) {
		return $var;
	}else {
		return NULL;
	}
}

// String trimming (array safe)
function safe_trim(&$value, $key=NULL) {
    if(is_array($value)) {
        array_walk($value, 'safe_trim');
    } elseif (is_string($value)) {
        $value = trim($value);
    }
}

// Strip unsafe commands and PHP/HTML tags from input variables
function clean_input_vars(&$inputvar, $key = '', $allowedTags = '') {
	if (is_array($inputvar)) {
		array_walk($inputvar, 'clean_input_vars', $allowedTags);
	} elseif (is_string($inputvar)) {
		$search[] = '/SELECT /i';
		$replace[] = 'S|ELECT ';
		$search[] = '/INSERT /i';
		$replace[] = 'I|NSERT ';
		$search[] = '/UPDATE /i';
		$replace[] = 'U|PDATE ';
		$search[] = '/EMPTY /i';
		$replace[] = 'E|MPTY ';
		$search[] = '/DROP /i';
		$replace[] = 'D|ROP ';
		$search[] = '/CREATE /i';
		$replace[] = 'C|REATE ';

		// Replace unsafe text
		$inputvar = preg_replace($search, $replace, $inputvar);

		// Strip tags
		while($inputvar != strip_tags($inputvar, $allowedTags)) {
				$inputvar = strip_tags($inputvar, $allowedTags);
		}

		// Add slashes
		if (!get_magic_quotes_gpc()) {
			$inputvar = addslashes($inputvar);
		}
	}
	return true;
}

function rte_safe($strText) {
	//returns safe code for preloading in the RTE
	$tmpString = trim($strText);

	//convert all types of single quotes
	$tmpString = str_replace(chr(145), chr(39), $tmpString);
	$tmpString = str_replace(chr(146), chr(39), $tmpString);
	$tmpString = str_replace("'", "&#39;", $tmpString);

	//convert all types of double quotes
	$tmpString = str_replace(chr(147), chr(34), $tmpString);
	$tmpString = str_replace(chr(148), chr(34), $tmpString);

	//replace carriage returns & line feeds
	$tmpString = str_replace(chr(10), " ", $tmpString);
	$tmpString = str_replace(chr(13), " ", $tmpString);

	return $tmpString;
}

// Locates system programs such as df, traceroute, whois
function locate_program($progname, $searchlocations) {
	GLOBAL $cfg;
	$fileperms = Array('-perm -700', '');
	$filetypes = Array('f', 'l');
	if (stristr($searchlocations, 'bin')) {
		$location = exec("which $progname");
		if (!empty($location)) {
			return $location;
		}
	}
	foreach($fileperms as $fperm) {
		foreach($filetypes as $ftype) {
			foreach($searchlocations as $sloc) {
				if (is_dir($sloc)) {
					$execstring = $cfg['prog']['find']." $sloc -name $progname -type $ftype $fperm";
					$location = exec($execstring);
					if (!empty($location))
					{
						return $location;
					}
				}
			}
		}
	}
	return '';
}

// Returns the ip that httpd and other internal services
//  should use depending on NAT status.
//
// On a Non-NAT server this will return the ip that its given
//  which is an external ip the server can use.
// On a NAT server this will return the internal ip that is
//  mapped to the given external ip
function get_server_ip($extip) {

	global $cfg;

	$ip[] = $extip;

	if ($cfg['NAT'] == true) {
		// Go through NAT Mappings
		for ($map = 1; $map <=6; $map++) {
			$mapdata = explode(',', $cfg['NAT-map'.$map]);
			$iip = $mapdata[0];
			$eip = $mapdata[1];
			 if ($eip == $extip) {
                                $iparr[] = $iip;
                        }
                }
                if (isset($iparr)) {
                        $ip = $iparr;
                }
	}
	return $ip;
}

function get_remote_ip() {
	$ip = !empty($_SERVER['CLIENT_IP']) ? $_SERVER['CLIENT_IP'] : '';
	$ip = !empty($_SERVER['HTTP_X_FORWARDED_FOR']) && empty($ip) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $ip;
	$ip = !empty($_SERVER['REMOTE_ADDR']) && empty($ip) ? $_SERVER['REMOTE_ADDR'] : $ip;
	return $ip;
}

// Check if the sysname is valid
//  Checks to ensure that $cfg['sysname'] has not been
//  invalidated accidently or set to an incorrect hostname or ip
//  Used for login. This may show sysname has not been tampered with
function check_sysname() {
	global $cfg;

	/* //allows for logins under virtualhost.domain.tld:port
	//for integrated mailman admin support
	if (substr_count($_SERVER['SERVER_NAME'], ":") != 0){
		$tsysname=explode(":",$_SERVER['SERVER_NAME']);
		$cfg['sysname'] = $tsysname[0];
	}elseif (substr_count($_SERVER['SERVER_ADDR'], ":") != 0){
                $tsysname=explode(":",$_SERVER['SERVER_ADDR']);
                $cfg['sysname'] = $tsysname[0];
        }elseif ($_SERVER['SERVER_NAME'] != "") $cfg['sysname']=$_SERVER['SERVER_NAME'];
	elseif ($_SERVER['SERVER_ADDR'] != "") $cfg['sysname']=$_SERVER['SERVER_ADDR'];
	else return false;
	return true;
	*/
        if (substr_count($_SERVER['SERVER_NAME'], ":") != 0)
		$tsysname=explode(":",$_SERVER['SERVER_NAME']);
	else
		$tsysname="";
	
	if ($cfg['sysname'] == $_SERVER['SERVER_NAME'])
		return true;
	elseif ($cfg['sysname'] == $_SERVER['SERVER_ADDR'])
		return true;
	elseif ($cfg['sysname'] == $tsysname[0])
		return true;
	elseif (gethostbyname($tsysname[0]) == $cfg['sysname'])
		return true;


	return false;
}

function file_size_info($filesize, $precision=2) {
	//For completeness sake
	$bytes = array('bytes', 'KB', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');

	for ($i = 0; $filesize > 1024; $i++)
		$filesize /= 1024;

	$file_size_info['size'] = round($filesize, $precision);
	$file_size_info['type'] = $bytes[$i];
	return $file_size_info;
}

// Return file size
function return_file_size($sizeInBytes,$precision=2) {
	$ret = file_size_info($sizeInBytes, $precision);
	return $ret['size'].' '.$ret['type'];
	//return ($sizeInBytes < 1024)?"$sizeInBytes bytes":round(($sizeInBytes / pow(1024,floor(log($sizeInBytes,1024)))),$precision)." ".substr(" KMGT",log($sizeInBytes,1024),1)."B";
}

// Safely strip an array
function strip_array($data) {
	while (list($key, $val) = each($data)) {
		if(!is_array($val))
			$data[$key] = trim(stripslashes($val));
		else
			$data[$key] = strip_array($val);
	}
	reset($data);

	return $data;
}

// Check a password to ensure it is relatively secure (not based on words, not crackable by cracklib)
function password_check($password) {
	$passarray[] = $password;
	$passarray[] = preg_replace("/[^a-z]/i","",$password);

    if (function_exists('pspell_check') && $pspell_config = pspell_config_create("en")) {
    	pspell_config_runtogether($pspell_config, true);
    	$pspell_link = pspell_new_config($pspell_config);
    	foreach ($passarray as $key) {
			if (pspell_check($pspell_link, $key)) {
				return false;
			}
		}
	}
	if (function_exists('crack_check') && $crack_dict = crack_opendict($cfg['cracklib_dict'])) {
		foreach ($passarray as $key) {
			if (!crack_check($crack_dict, $key)) {
				crack_closedict($crack_dict);
				return false;
			}
		}
		crack_closedict($crack_dict);
	}
	return true;
}

// Get a file type
function ftp_file_type($file, $file_types) {
/* match filename against a regex and return the file type */
	// strip all but extension
	$ext = substr($file, (strrpos($file, '.')));
	$ext = str_replace('.', '',  $ext);
	// find file type
	foreach($file_types AS $key => $regex) {
		if (eregi('^('.$regex.')$', $ext)) {
			$type = $key;
		}
	}
	// if type not found return 'other'
	if (!isset($type)) $type = 'other';
	return $type;
}

// Send a cookie
function send_cookie($name, $value, $expires, $path, $domain, $secure = 0) {
/* same as php's setcookie() */
	global $cfg;
	if ($cfg['httpd_mode'] == 'apache') {
		return setcookie($name, $value, $expires, $path, $domain, $secure);
	}else {
		/* expires must follow the format: Saturday, 06-Sep-2014 23:50:08 GMT */
		$expires = date("l, d-M-Y H:i:s \G\M\T", $expires);
		return send_header("Set-Cookie: $name=$value; expires=$expires; path=$path; domain=$domain; $secure", false);
	}
}

// Send a header
function send_header($header, $replace = true) {
/* same as php's header() except doesn't support the
 * optional http_reponse_code parameter */
	global $cfg, $send_headers, $header_redirect;
	if ($cfg['httpd_mode'] == 'apache') {
		header($header, $replace);
	} else {
		if ($replace) {
			/* if replace is true (default) overwrite any alike headers */
			$header_name = explode(":", $header);
			$send_headers[strtolower($header_name[0])] = $header."\r\n";
		} else {
			/* otherwise give them a unique number */
			$send_headers[] = $header."\r\n";
		}
	}
	/* location headers are a special case, we have to let send_response()
	 * know to change the response status to redirect */
	if (stristr($header, 'Location:')) {
		$header_redirect = true;
	}
	return true;
}

//  Convert bytes
function convert_bytes($size, &$metric, $from = 'b', $to = '') {
/* used for byte conversion. $from should contain the unit
 * of measurement that $size is currently in. if $to is not
 * provided this function will return the largest unit of
 * measurement. The $metric variable will contain the final
 * unit of measurement used. */
	if (!is_numeric($size)) {
		return false;
	}
	/* amounts in bytes */
	$m['b'] = 1;			// Byte
	$m['kb'] = 1024;		// Kilobyte
	$m['mb'] = 1048576;		// Megabyte
	$m['gb'] = 1073741824;		// Gigabyte
	$m['tb'] = 1099511627776;	// Terabyte
	$m['pb'] = 1125899906842624; 	// Petabyte
	$m['eb'] = 1152921504606847000;	// Exabyte
	/* we work in bytes, so multiply size by the variable that corresponds to 'from' */
	if (!empty($m[$from])) {
		$size = $size * $m[$from];
	}else {
		return false;
	}
	if (isset($m[$to])) {
		$metric = $to;
	}else {
		/* 'to' was not provided, so just return the largest increment */
		$last = 'b';
		foreach ($m AS $key => $val) {
			if ($size < $val) {
				$metric = $last;
				break;
			}
			$last = $key;
		}
	}
	/* convert the size, which is in bytes now, to the requested metric */
	return round($size / $m[$metric], 2);
}

// Function:	service()
// Utility:	Request system services to stop,start,restart or server to reboot.
// Usage:	service(ACTION[,SERVICE,HOST])
// Examples:	service("restart","network","servername.com");
//				service("reboot","","servername.com");
// Definitions:	ACTION:	stop,start,restart [service], reboot
//		SERVICE:(optional)	Used with actions stop,start,restart: any registered program in the sysv init dir.
//		HOST:	(optional) Target Host, default to localhost
function service($action,$service,$host = 'localhost') {
	// Get Configurations configurations, Language file, regex, userdata
	GLOBAL $cfg, $T, $rx, $userdata;
	// Set error 'counter'
	$i = 1;
	//
	// Verify input $data

	// Action validity
	if (!eregi($rx['word'],$action))
		$error[$i++] = $T['err']['service']['action'];
	// Service validity
	if ((!eregi($rx['alnum'],$service)) && ($action != "reboot"))
		$error[$i++] = $T['err']['service']['service'];
	// Action host
	if (!eregi($rx['service'],$host))
		$error[$i++] = $T['err']['service']['host'];

	// If there are any errors, stop; else commit action
	if (is_array($error)) return $error;
	else
		commit($action,$service,$host);
	// Log it
	webcp_log(2,$userdata['id'],$userdata['username'],"service : $action $service",$_SERVER['REMOTE_ADDR']);
}

// Function:	commit()
// Utility:	This is the link between web-cp interface and web.cp CGI daemon.  Request system updates, etc.
// Usage:	commit(ACTION, [EXTRA], [HOST])
// Examples:
//    commit('scan');
//		commit("restart","httpd","servername.com");
// Definitions:
//    ACTION:	scan (system update), read (check flag presence), stop,start,restart [service], reboot, sanity(system<=>db check)
//		EXTRA:	(optional) Used with actions stop,start,restart: any registered program in the sysv init dir.
//		HOST:	(optional) Target Host, default to localhost
function commit($action,$extra = '',$host = 'localhost') {
	// Get Configurations
	GLOBAL $cfg;

	// web-cp file 'tag'
	$tag = $cfg['basedir']."/tag/.webcp";
	//??? $tag2 = $cfg['basedir']."/sqltag/.webcp"; // remote notice by MySQL

	//So filesize() is updated
	clearstatcache();

	// Read return the first line of the tag file if it exists
	// Make sure you only call this from the backend and when you plan to process
	// the action, because it will remove the action from the tag file
	if ($action == 'read') {

		// Only read flag if one exists and it's not empty
		if (file_exists($tag) && filesize($tag) > 0) {
			$fp = fopen($tag, 'r+');

			flock($fp, LOCK_EX);

			// Get first action
			$line = fgets($fp);

			// Remove first line from file
			$remainder = fread($fp, 4096);
			fseek($fp, 0, SEEK_SET);
			ftruncate($fp, 0);
			fwrite($fp, $remainder);

			flock($fp, LOCK_UN);
			fclose($fp);

			list($action, $seal, $extra) = explode(' ', $line, 3);

			if(!verify_seal($seal, $action)) {
				webcp_log(0,0,"system","Error: invalid server update request (Invalid Tag Seal)",0);

				return false;
			}

			return array('action' => array($action, $extra));

		} else
			return false;
	}

	// Remove the first line of the tag file
	elseif ($action == 'remove' ) {
		//Do nothing, this is done by the read action

	// Append new action
	} else {
		//We use fread() with a max size of 4096 (which is about 32+ entries)
		if(file_exists($tag) && filesize($tag) > 4096)
			return false;

		$seal = make_seal($action);
		$line = "$action $seal $extra\n";

		if (file_exists($tag))
			$fp = fopen($tag, 'r+');
		else
			$fp = fopen($tag, 'w+');

		flock($fp, LOCK_EX);

		if($action == 'scan') {
			// If a scan action exists, it's always first
			if(fread($fp, 5)=='scan ') {
				// Add scan action only if one doesn't exist already
				flock($fp, LOCK_UN);
				fclose($fp);

				return true;
			}

			fseek($fp, 0, SEEK_SET);

			$contents = $line.fread($fp, 4096);
		} else
			$contents = fread($fp, 4096).$line;

		// Seek to start of file ready for write
		fseek($fp, 0, SEEK_SET);

		fwrite($fp, $contents);

		flock($fp, LOCK_UN);
		fclose($fp);

		return true;
	}
}

// Function:	get_dir_list()
// Utility:	List [recursively or not] directories or files, can use simple search patern
// Usage:	get_dir_list(ROOT,TYPE[,SEARCH])
// Examples:	get_dir_list($personaldata['root'],"all");
//		get_dir_list($domaindata['path'],"dir",'.gif$');
// Definitions:	ROOT:	root dir to list
//		TYPE:	type of listing: all, dir, files
//		SEARCH:	search pattern: simple REGEX.
//		LIMIT:	how deep to list dirs, default unlimited
// Return:	array: directory structure.
//
// Modified:    Removed exec, replaced with recursive get_dir_list function
function get_dir_list(&$listing, $dirName, $filetoo, &$count) {
	if(is_readable($dirName)) {
		if (is_dir($dirName)) {
			 $d = dir($dirName);
			 $listing[$count] = $dirName;
			 $count++;
			 while($entry = $d->read()) {
				if(is_readable($dirName."/".$entry)) {
				   if (($entry != ".") && ($entry != "..") && ($entry != "")) {
					   if (is_dir($dirName."/".$entry)) {
						   get_dir_list($listing,$dirName."/".$entry,$filetoo,$count);
					   }else {
						   if ($filetoo) { $listing[$count] = $dirName."/".$entry; $count++; }
					   }
				   }
				 }
			 }
			 $d->close();
		}
	}
}

// Directory list
function dir_list($root, $type, $search='', $limit='none') {
	// Get Configurations
	GLOBAL $cfg;
        $dirstruct = array();
        $count = 0;

	// Set find type
	if ($type == "dir") $type = "d";
   	elseif ($type == "file") $type = "f";
   	else unset($type);

	clearstatcache();
	//      if ($type) exec("find '$root' -type $type",$dirstruct);
	//      else exec("find '$dir'",$dirstruct);
    if ($type=="d") get_dir_list ($dirstruct, $root,0,$count);
    else get_dir_list ($dirstruct, $root, 1, $count);
	return $dirstruct;
}

// Function:	get_stat()
// Utility:	Gets system stat: uptime, monitor status, memory, swap, cpu load.
// Usage:	get_stat(TYPE)
// Examples:	get_stat("uptime");
//		get_stat("cpu");
// Definitions:	TYPE:	uptime, ram, swap, cpu, monitor
// Returns:	array: ['http'], ['total'], etc
// Modified:    Changed shell_exec statements to file read of data generated by cron/monitor.inc.phps
function get_stat($action) {
	// Get Configurations
	GLOBAL $cfg;

	// initialize
	unset($return);

	$filepath = $cfg['basedir']."/server/data/";

	// Select what to do based on the action
	switch($action) {
		case 'ram':
			if($cfg["os"] == "linux") {
				$filename = $filepath."ram.dat";
				if (file_exists($filename)) {
					$serverinfo = file($filename);
					$serverinfo = implode("",$serverinfo);
					$serverinfo = explode(" / ",$serverinfo);
					$return['total'] = $serverinfo[1];
					$return['used'] = $serverinfo[0];
				} else {
					$return['total'] = -1;
					$return['used'] = -1;
				}
			}
			elseif($cfg["os"]=="freebsd") {
				$return['total'] = (int)(trim(`sysctl -n hw.physmem`)/pow(1024, 2));
				$return['used'] = (int)(trim(`vmstat | tail -n 1 | cut -c8-16`)/1024);
			}

			break;

		case 'swap':
			if ($cfg["os"] == "linux") {
				$filename = $filepath."swap.dat";
				if (file_exists($filename)) {
					$serverinfo = file($filename);
					$serverinfo = implode("",$serverinfo);
					$serverinfo = explode(" / ",$serverinfo);
					$return['total'] = $serverinfo[1];
					$return['used'] = $serverinfo[0];
				} else {
					$return['total'] = -1;
					$return['used'] = -1;
				}
			}
			elseif($cfg["os"] == "freebsd") {
				// $swapinfo contains swap info for each disk
				exec("swapinfo | sed -e '1d'", $swapinfo);
				foreach($swapinfo as $disk){
					// find Used and Avail on this disk
					preg_match("/^(\S+\s+){2}(\S+)\s+(\S+)/", $disk, $matches);
					// Add to totals:
					$return["used"]+=$matches[2];
					$return["total"]+=$matches[3];
				}
				$return["used"]=(int)($return["used"]/1024);
				$return["total"]=(int)($return["total"]/1024);
			}
			break;

		case 'cpu':
		case 'uptime':
			// check for how long its been up and parse accordingly
			if($cfg["os"]=="linux"){
				$filename = $filepath."uptime.dat";
				if (file_exists($filename)) {
					$serverinfo = file($filename);
					$serverinfo = implode("",$serverinfo);
				} else {
					$serverinfo = '';
				}
			} elseif($cfg["os"]=="freebsd") {
				$serverinfo = trim(`uptime | cut -c10-`);
			}

			if (strstr($serverinfo,"day")) {
				$serverinfo = explode(",",$serverinfo);
				$return['uptime'] = trim(str_replace("up","",$serverinfo[0].", ".$serverinfo[1]));
				$return['cpu'] = (trim(str_replace("load average: ","",$serverinfo[3]))." : ".trim($serverinfo[4])." : ".trim($serverinfo[5]));
			} else {
				if (strlen($serverinfo)) {
					$serverinfo = explode(",",$serverinfo);
					$return['uptime'] = trim(str_replace("up","",$serverinfo[0]));
					$return['cpu'] = (trim(str_replace("load average: ","",$serverinfo[2]))." : ".trim($serverinfo[3])." : ".trim($serverinfo[4]));
				} else {
					$return['uptime'] = -1;
					$return['cpu'] = -1;
				}
			}
			break;

		case 'monitor':
			// load config file and parse it for HOST	localhost
			$filename = $cfg['basedir']."/server/data/sysmon.dat";
			if (file_exists($filename)) {
				$return = file($filename);
				$return = implode("",$return);
				$return = unserialize($return);
				if (fileatime($cfg['basedir'].$cfg['statustag']) > (time() - 90)) {
					$return['webcpbackend'] = 'up';
				}else {
					$return['webcpbackend'] = 'down';
				}
			}
			else return $T['err']['getstat']['no monitor data'];
			break;
	}
	return ($return);
}

// Function:	fetchdata()
// Utility:	Quickly fetch data without using SQL statements; trim, remove slashes & parse as well
// Usage:	fetchdata(SELECT_COL,TYPE,WHERE)
// Examples:	fetchdata("*","user",$username);
//		fetchdata("host,domain","domain",$personaldata['id']);
//		fetchdata("users","total",$domainid);
// Return:	$data 		array var (SQL data fetched)  or nothing
// Definitions:	SELECT_COL:	Column name(s) to fetch (corresponding to the MySQL Tables)
//		TYPE:		user, domain, reseller, total, alloc
//		WHERE:		user: username, domain: ID, reseller: ID
function fetchdata($select_col,$type,$where) {
	// get configurations
	GLOBAL $cfg;

	$data = Array();

	$ret = Array('where' => $where, 'type' => $type);
	call_hook('fetchdata:'.$type.':'.$select_col, $ret);
	$i = 0;

	if (isset($ret['name']) && is_array($ret['name'])) {
		foreach($ret['name'] as $fieldname) {
			$data[$fieldname] = $ret['value'][$i++];
		}
	} elseif (isset($ret['name'])) {
		$data[$ret['name']] = $ret['value'];
	}

	// Initialize
	unset($tmp);
	// type is 'user'
	if ($type == "user") {
		// Safety check for older code.
		if(!is_array($where)) {
			echo 'WARNING: Outdated code. fetchdata() for user should be called with an array with both the username and the domain id as params.'."\n";
			return NULL;
		}

		$dbp = mysql_query("SELECT $select_col FROM users WHERE username='".$where[0]."' AND id = ".$where[1]);
		if ($dbp) {
			$userdata = mysql_fetch_array($dbp);
		}
		if ($userdata) {
			reset($userdata);
			$j = 0;
			do {
				$key = key($userdata);
				if ($key != $j) {
					// if col_name == password, decode it
					if ($key == "password") {
						$dbp2 = mysql_query("SELECT DECODE(password,'".$cfg['key']."') AS password FROM users WHERE username='".$where[0]."' AND id = ".$where[1]." LIMIT 1");
						$data2 = mysql_fetch_array($dbp2);
						$userdata['password'] = trim(stripslashes($data2['password']));
					}
					else {
						// clean the data (no slashes, no leading spaces)
						$userdata[$key] = trim(stripslashes(current($userdata)));
					}
				}
				else ++$j;
			}while (next($userdata) OR isset($userdata[$j]));
			$data += $userdata;
		}
	}

	// type is 'domain'
	elseif ($type == "domain") {

		// fetch data from SQL db
		$SQL = "SELECT $select_col FROM domains WHERE id='$where'";
		if ($dbp = mysql_query($SQL)) {
		// clean the data (no slashes, no leading spaces)
		if ($domaindata = mysql_fetch_array($dbp)) {
			reset($domaindata);
			$j = 0;
			do {
				$key = key($domaindata);
				if ($key != $j) {
					// if col_name == serverside or databases, unserialize it

					if ($key == "serverside") {
						$domaindata[$key] = unserialize(current($domaindata));
					} else {
						// clean the data (no slashes, no leading spaces)
						$domaindata[$key] = trim(stripslashes(current($domaindata)));
					}
				}
				else ++$j;
			}while (next($domaindata) OR isset($domaindata[$j]));
			$data += $domaindata;
		}
		}
	}

	// type is 'reseller'
	elseif ($type == "reseller") {

		// only get reseller ID (5 first numbers)
		$where = substr($where, 0, 5);

		// fetch data from SQL db
		if ($dbp = mysql_query("SELECT $select_col FROM resellers WHERE id='$where'")) {
			$resellerdata = mysql_fetch_array($dbp);
		}

		if ($resellerdata) {
			reset($resellerdata);
			$j = 0;
			do {
				$key = key($resellerdata);
				if ($key != $j) {
					// if col_name == serverside, unserialize it
					if ($key == "serverside") {
						$resellerdata[$key] = unserialize(trim(stripslashes(current($resellerdata))));
					}
					else {
						// clean the data (no slashes, no leading spaces)
						$resellerdata[$key] = trim(stripslashes(current($resellerdata)));
					}
				}
				else ++$j;
			}while (next($resellerdata) OR isset($resellerdata[$j]));

			$data += $resellerdata;
		}
	}
	// type is 'total'
	elseif ($type == "total") {
		if ($select_col == "users") {
			// if $where == 0, get all users
			if ($where == 0)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM users");
			// if $where < 1000000000, get a reseller's users
			elseif ($where < 1000000000)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM users WHERE id >= ".$where."10000 AND id <= ".$where."99999");
			// else get a domain's users
			else
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM users WHERE id='$where'");
		}
		elseif ($select_col == "resellers") {
			if ($where == 0)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM resellers");
		}
		elseif ($select_col == "hd") {
			// if $where == 0, get all hd space
			if ($where == 0)
				$dbp = mysql_query("SELECT SUM(hd_used) AS $select_col FROM domains");
			// else get a reseller's total hd space
			else
				$dbp = mysql_query("SELECT SUM(hd_used) AS $select_col FROM domains WHERE owner='$where'");
		}
		elseif ($select_col == "db") {
			// if $where == 0, get all databases
			if ($where == 0) {
				// Get current reseller's domains' user list
				$dbp = mysql_query("SELECT username FROM users WHERE type != 'demo' ORDER BY username");
				while ($tmp = mysql_fetch_array($dbp)) {
					$utmp = substr($tmp['username'],0,16);
					if ($userlist[$j-1] != $utmp)
						$userlist[$j++] = $utmp;
				}
				if (sizeOf($userlist) > 0) {
					// Select mysql database
					mysql_select_db('mysql');
					// Count databases in use
					$sql_query  = "SELECT count(db) AS $select_col FROM db WHERE ";
					$sql_query .= "User='".implode("' OR User='",$userlist);
					$sql_query .= "'";
					$dbp1 = mysql_query($sql_query);
					$mysqlrow = mysql_fetch_array($dbp1);
					// Return to web-cp database
					mysql_select_db($cfg['dbname']);

					if ($cfg['user_pgsql']) {
						if ($psql = @pg_connect("host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$cfg['pgsql_db'])) {
							$sql_query = "SELECT count(datname) as $select_col FROM pg_database inner join pg_user ON datdba = usesysid WHERE ";
							$sql_query .= "usename='".implode("' OR usename='",$userlist);
							$sql_query .= "'";
							$dbp2 = pg_query($psql, $sql_query);
							$pgsqlrow = pg_fetch_array($dbp2);
						}

						unset($dbp);
						$data[$select_col] = intval($mysqlrow[$select_col]) + intval($pgsqlrow[$select_col]);
					}else {
						unset($dbp);
						$data[$select_col] = intval($mysqlrow[$select_col]);
					}

				}else {
					$dbp[$select_col] = 0;
				}
			}
			// get a reseller's dbs
			elseif ($where < 1000000000) {
				// Get current reseller's domains' user list
				$dbp = mysql_query("SELECT username FROM users WHERE type != 'demo' AND id >= ".$where."10000 AND id <= ".$where."99999 ORDER BY username");
				while ($tmp = mysql_fetch_array($dbp)) {
					$utmp = substr($tmp['username'],0,16);
					if ($userlist[$j-1] != $utmp)
						$userlist[$j++] = $utmp;
				}
				if (sizeOf($userlist) > 0) {
					while ($tmp = mysql_fetch_array($dbp)) {
					$utmp = substr($tmp['username'],0,16);
					if ($userlist[$j-1] != $utmp)
						$userlist[$j++] = $utmp;
					}
				}
				if (sizeOf($userlist) > 0) {
					// Select mysql database
					mysql_select_db('mysql');
					// Count databases in use
					$sql_query  = "SELECT count(db) AS $select_col FROM db WHERE ";
					$sql_query .= "User='".implode("' OR User='",$userlist);
					$sql_query .= "'";
					$dbp1 = mysql_query($sql_query);
					$mysqlrow = mysql_fetch_array($dbp1);
					// Return to web-cp database
					mysql_select_db($cfg['dbname']);

					if ($cfg['user_pgsql']) {
						if ($psql = @pg_connect("host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$cfg['pgsql_db'])) {
							$sql_query = "SELECT count(datname) as $select_col FROM pg_database inner join pg_user ON datdba = usesysid WHERE ";
							$sql_query .= "usename='".implode("' OR usename='",$userlist);
							$sql_query .= "'";
							$dbp2 = pg_query($psql, $sql_query);
							$pgsqlrow = pg_fetch_array($dbp2);
						}

						unset($dbp);
						$data[$select_col] = intval($mysqlrow[$select_col]) + intval($pgsqlrow[$select_col]);
					}else {
						unset($dbp);
						$data[$select_col] = intval($mysqlrow[$select_col]);
					}
				}else {

					$data[$select_col] = 0;
				}
			}
			// else get a domain's databases
			else  {
				// Get current domain's domains user list
				$SQL = "SELECT username FROM users WHERE type != 'demo' AND id = '$where' ORDER BY username";
				$dbp = mysql_query($SQL);
				while ($tmp = mysql_fetch_array($dbp)) {
					$utmp = substr($tmp['username'],0,16);
					if ($userlist[$j-1] != $utmp)
						$userlist[$j++] = $utmp;
				}

				if (sizeOf($userlist) > 0) {
					while ($tmp = mysql_fetch_array($dbp)) {
					$utmp = substr($tmp['username'],0,16);
					if ($userlist[$j-1] != $utmp)
						$userlist[$j++] = $utmp;
					}
				}
				if (sizeOf($userlist) > 0) {
					// Select mysql database
					mysql_select_db('mysql');
					// Count databases in use
					$sql_query  = "SELECT count(db) AS $select_col FROM db WHERE ";
					$sql_query .= "User='".implode("' OR User='",$userlist);
					$sql_query .= "'";
					$dbp1 = mysql_query($sql_query);
					$mysqlrow = mysql_fetch_array($dbp1);
					// Return to web-cp database
					mysql_select_db($cfg['dbname']);

					if ($cfg['user_pgsql']) {
						if ($psql = @pg_connect("host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$cfg['pgsql_db'])) {
							$sql_query = "SELECT count(datname) as $select_col FROM pg_database inner join pg_user ON datdba = usesysid WHERE ";
							$sql_query .= "usename='".implode("' OR usename='",$userlist);
							$sql_query .= "'";
							$dbp2 = pg_query($psql, $sql_query);
							$pgsqlrow = pg_fetch_array($dbp2);
						}
						unset($dbp);
						$data[$select_col] = intval($mysqlrow[$select_col]) + intval($pgsqlrow[$select_col]);
					}else {
						unset($dbp);
						$data[$select_col] = intval($mysqlrow[$select_col]);
					}
				}else {
					unset($dbp);
				}
			}
		} elseif ($select_col == "domains") {
			// only get reseller ID (5 first numbers)
			$where = substr($where, 0, 5);
			// if $where == 0, get all domains
			if ($where == 0)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE type = 'domain'");
			// else get a reseller's domains
			else
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE owner = '$where' AND type = 'domain'");
		}
		elseif ($select_col == "subdomains") {
			// if $where == 0, get all subs
			if ($where == 0)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE type = 'subdomain'");
			// if $where < 1000000000, get a reseller's subs
			elseif ($where < 1000000000)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE id >= ".$where."10000 AND id <= ".$where."99999 AND type = 'subdomain'");
			// else get a domain's subs
			else
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE owner = '$where' AND type = 'subdomain'");
		}
		elseif ($select_col == "pointers") {
			// if $where == 0, get all pointers
			if ($where == 0)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE type = 'pointer'");
			// if $where < 1000000000, get a reseller's pointers
			elseif ($where < 1000000000)
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE owner >= ".$where."10000 AND owner <= ".$where."99999 AND type = 'pointer'");
			// else get a domain's pointers
			else
				$dbp = mysql_query("SELECT COUNT(*) AS $select_col FROM domains WHERE owner = '$where' AND type = 'pointer'");
		}

		// fetch data from SQL db
		if (!is_null($dbp)) {
			if (mysql_num_rows($dbp)) {
				$data = mysql_fetch_array($dbp);
			} else {
				$data = '';
			}
		}elseif (!is_array($data)) {
			$data = "";
		}
	}

	// type is 'alloc'
	elseif ($type == "alloc") {
		switch($select_col) {
			case 'mm':
			case 'db':
			case 'users':
			case 'hd':
			case 'subdomains':
			case 'pointers':
				if ($where > 0) {
					$SQL = "SELECT SUM($select_col) AS $select_col FROM domains WHERE $select_col != -1 AND owner='$where'";
					$dbp = mysql_query($SQL);
				}else {
					$SQL = "SELECT SUM($select_col) AS $select_col FROM domains WHERE $select_col != -1";
					$dbp = mysql_query($SQL);
				}
				break;
			case 'domains':
				$dbp = mysql_query("SELECT SUM($select_col) AS $select_col FROM resellers WHERE $select_col != -1");
				break;
			case 'resellers':
				$dbp = mysql_query("SELECT COUNT(id) AS $select_col FROM resellers");
				break;
			default:
				break;
		}

		// fetch data from SQL db
		if ($dbp) {
			if (mysql_num_rows($dbp)) {
				$data = mysql_fetch_array($dbp);
			} else {
				$data = "";
			}
		} elseif (!is_array($data)) {
			$data = "";
		}
	}
	if (is_array($data)) {
		$ii = 0;
		while(isset($data[$ii]))
			unset($data[$ii++]);
	}

	// Return fetched data, or null if nothing
	return($data);
}

// Function:	user()
// Utility:	Create, Delete, Modify, Suspend, Unsuspend users; make sure everything is ok & secure
// Usage:	user(ACTION,DATA)
// Examples:	user("create",$_POST);
//		user("delete",$username);
// Return:	$error		array var or nothing
// Definitions:	ACTION:		create, delete, modify, suspend, unsupend
//		DATA:		username, HTTP_POST_VARS, etc
function user($action,$data) {
	// Get configurations, userdata, Language file, regex
	GLOBAL $userdata, $cfg, $T, $rx;

	// kill demo users (return error)
	if ($userdata['type'] == "demo") {
		$error[1] = $T['err']['demo user'];
		return $error;
	}

	// Set error 'counter'
	$i = 1;

	//
	// Create a new user entry in the database
	if ($action == "create") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain group id that will hold the user
		//
		//
		// Expected Input Data (from POST)
		// ===============================
		// * Optional
		// data[name]		Full Name
		// data[username]	username
		// data[password]	password
		// data[root]		/path-to/user-root.  web-cp will add the start of the string (HOME).
		// data[type]		type of user: standard,virtual,email,ftp,database,demo
		// data[level]		Level: 1-5 (server, reseller, domain, personal, tools)
		// data[hd]		HD Quota
		// data[aliases]	* Default: none; e-mail aliases seperated by space, coma or new lines
		// data[catchall]	* Catch all mail non catched by another user first.  Once per domain.
		// data[shell]		* Default: off; on,off,ask
		// data[autoreply]	* E-Mail Auto-Responder message
		// data[forward]	* Addresses to forward to
		// data[lang]		* User Language. Default: #defaultlang
		// data[skin]		* Interface skin. Default: #defaultskin


		// Fetch some data to respect Quotas & verify some input validity
		$dom_data = fetchdata("hd,users,shell,host","domain",$data['id']);
		$users = fetchdata("users","total",$data['id']);


		//
		// Verify input $data

		// Name validity
		if (!eregi($rx['name'],$data['name']))
			$error[$i++] = $T['err']['user']['name'];
		// Username validity
		if (eregi($rx['user'],$data['username'])) {
			$data['username'] = strtolower($data['username']);
			$dbp = mysql_query("SELECT username FROM users WHERE username = '".$data['username']."' AND id = '".$data['id']."'");
			if (mysql_num_rows($dbp) OR stristr($cfg['badusers'],' '.$data['username'].' '))
				$error[$i++] = $T['err']['user']['used username'];
		} else
			$error[$i++] = $T['err']['user']['username'];

		// Password
		if (!eregi($rx['pass'],$data['password'])) $error[$i++] = $T['err']['user']['password'];
		if ($cfg['strong_passwords'])
			if (!password_check($data['password'], $error)) $error[$i++] = $T['err']['user']['weakpassword'];
		// Escape ' and " for MySQL.
		$data['password'] = addslashes($data['password']);

		// User Root Validity
		if (!$data['root'])
			$data['root'] = $cfg['webdir']."/".$data['id'];
		else {
			$dir = ereg_replace("^/","",str_replace("../","",$data['root']));
			$dir = $cfg['webdir']."/".$data['id']."/".$dir;
			$dir = ereg_replace("/$","",$dir);
			if (strstr($dir,"%USER%")) {
				$tmp = explode("%USER%",$dir);
				if (!is_dir($tmp[0]))
					$error[$i++] = $T['err']['user']['root'].$tmp[0];
				$dir = $tmp[0].$data['username'].str_replace("/","",$tmp[1]);
			}
			else {
				if (!is_dir($dir))
					$error[$i++] = $T['err']['user']['root'].$dir;
			}
			$data['root'] = $dir;
		}


		// Aliases validity, unique
		$aliases = split("([[:space:]]+,?|[[:space:]]*,)",strtolower($data['aliases']));
		if (is_array($aliases) AND trim($data['aliases'])) {
			$rmalias = '';
			do {
				// is it valid?
				if (eregi($rx['alias'],current($aliases))) {
					// verify if its not used as a user already
					$dbp = mysql_query("SELECT username FROM users WHERE username = '".current($aliases)."' AND id = '".$data['id']."'");
					if (mysql_num_rows($dbp))
						$error[$i++] = $T['err']['user']['aliases'].current($aliases);

					// verify if its not used as an alias already
					$dbp = mysql_query("SELECT username FROM users WHERE aliases LIKE '% ".current($aliases)." %' AND id = '".$data['id']."'");
					if (mysql_num_rows($dbp))
						$error[$i++] = $T['err']['user']['aliases'].current($aliases);

					if (current($aliases) == $data['username'])
						$rmalias = current($aliases);
				}
				// not valid
				else
					$error[$i++] = $T['err']['user']['aliases'].current($aliases);
			} while(next($aliases));

			// Reset $data['aliases'] to a correct value.  The trailing spaces are needed for fast searching (step above)
			$data['aliases'] = " ".trim(implode(" ",$aliases))." ";
			if ($rmalias)
				str_replace(" $rmalias ", " ",$data['aliases']);
			$data['aliases'] = ereg_replace("[[:space:]]+"," ",$data['aliases']);
		}
		// there is no aliases, unset it.
		else
			unset($data['aliases']);

		// Check for catchall
		if ($data['catchall'] == "true") {
			$dbp = mysql_query("SELECT username FROM users WHERE catchall = 'true' AND id = '".$data['id']."'");
				if ($tmp = mysql_fetch_array($dbp))
					$error[$i++] = $T['err']['user']['catchall'].$tmp['username'];
		}
		else $data['catchall'] = "false";

		// Verify User type:  standard, virtual, email, ftp, database or demo
		switch($data['type']) {
			case 'standard':
			case 'database':
			case 'demo':
				break;
			case 'ftp':
				if ($cfg['ftpserver'] == "proftpd")
					break;
			case 'email':
				if ($cfg['mailserver'] == "virtualqmail")
					break;
			case 'virtual':
				if ($cfg['ftpserver'] == "proftpd" AND $cfg['mailserver'] == "virtualqmail")
					break;
			default:
				$error[$i++] = $T['err']['user']['type'];
		}

		// Verify User Level
		$data['level'] = intval($data['level']);
		if ($data['level'] < $userdata['level'])
			$error[$i++] = $T['err']['user']['level'];

		// Verify HD & Users availability
		$data['hd'] = intval($data['hd']);
		if ($dom_data['hd'] < $data['hd'] && $dom_data['hd'] != -1)
			$error[$i++] = $T['err']['user']['hd'].$dom_data['hd'];
		if ($dom_data['users'] - $users['users'] <= 0 && $dom_data['users'] != -1)
			 $error[$i++] = $T['err']['user']['user'];

		// Verify Shell
		if ($data['shell'] == "on") {
			if ($dom_data['shell'] != "on")
				$error[$i++] = $T['err']['user']['shell'];
		}
		else $data['shell'] = "off";

		// Autoresponder Check
		$data['autoreply'] = addslashes($data['autoreply']);

		// E-Mail Forwarding
		$forward = split("([[:space:]]+,?|[[:space:]]*,)",$data['forward']);
		if (is_array($forward) AND trim($data['forward'])) {
			do {
				// is it not valid?
				if (!eregi($rx['eml'],current($forward)) AND !eregi($rx['user'],current($forward)))
					$error[$i++] = $T['err']['user']['forward'].current($forward);
			} while(next($forward));

			// Reset $data['forward'] to a correct value.
			$data['forward'] = trim(implode(" ",$forward));
		}
		// there is no forwarding, unset it.
		else
			unset($data['forward']);

		// Set User's Language
		if (!ereg("^".$data['lang']."$",$cfg['lang']) AND
		    !ereg("^".$data['lang']."[:space:]*,",$cfg['lang']) AND
		    !ereg(",[:space:]*".$data['lang']."$",$cfg['lang']) AND
		    !ereg(",[:space:]*".$data['lang']."[:space:]*,",$cfg['lang']))
			$data['lang'] = $cfg['defaultlang'];

		// Set User's web-cp skin
		$data['skin'] = str_replace("/","",$data['skin']);
		if (!trim($data['skin']) OR !file_exists("skin/".$data['skin']))
			$data['skin'] = $cfg['defaultskin'];


		//
		// Insert into Database
	
		// If any error occured before, return it now
		if (is_array($error)) {
			return $error;
		}
		else {
			$SQL = "INSERT INTO users SET id='".$data['id']."', username='".$data['username']."', username1='".$data['username']."', name='".addslashes($data['name'])."', root='".$data['root']."',
				password=ENCODE('".$data['password']."','".$cfg['key']."'), type='".$data['type']."', level='".$data['level']."', hd='".$data['hd']."',
				aliases='".$data['aliases']."', shell='".$data['shell']."', autoreply='".$data['autoreply']."', forward='".$data['forward']."', catchall='".$data['catchall']."',
				lang='".$data['lang']."', skin='".$data['skin']."', action='create'";
				
			if (mysql_query($SQL)) {

				// create md5 signature and insert it.
				$hash = fetchdata("*","user",Array($data['username'], $data['id']));
				$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
				$hash = crypt(md5(serialize($hash)), $cfg['key']);
				mysql_query("UPDATE users SET hash='$hash' WHERE username = '".$data['username']."'");

				// Log it
				webcp_log(2,$userdata['id'],$userdata['username'],"user created: ".$data['username'],$_SERVER['REMOTE_ADDR']);

				// Tell the system to commit the changes.
				commit("scan");
			} else {
				$error[$i++] = $T['err']['SQL'];
				return $error;
			}
		}

	}
	// end 'create'
	///


	//
	// Update an user entry in the database
	if ($action == "update") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[uid]	*REQUIRED* username
		// data[id]	*REQUIRED* group ID#
		//
		//
		// Expected Input Data (from POST)
		// ===============================
		// ** ALL Optional
		// data[name]		Full Name
		// data[username]	new username
		// data[password]	new password
		// data[pass_confirm]	1 if confirmed -- needed for data[password]
		// data[root]		/path-to/user-root.  web-cp will add the start of the string (HOME).
		// data[level]		Level: 1-5 (server, reseller, domain, personal, tools)
		// data[hd]		HD Quota
		// data[shell]		on,off,ask
		// data[lang]		User Language.
		// data[skin]		Interface skin.
		// data[aliases]	E-mail aliases seperated by space, coma or new lines
		// data[autoreply]	E-Mail Auto-Responder message
		// data[forward]	Addresses to forward to seperated by space, coma or new lines
		// data[catchall]	Catch all mail non catched by another user first.  Once per domain.
		// data[ip_restrict]	IP restriction on the account.  Can match all or part of an IP Address.

		// Fetch some usefull data to verify input validity
		$personaldata = fetchdata("*","user",Array($data['uid'], $data['id']));
		$dom_data = fetchdata("hd,shell","domain",$personaldata['id']);

		if ($userdata['level'] > $personaldata['level']) {
			$error[1] = $T['err']['user higher'];
			return $error;
		}

		// Check update count
		if ($personaldata['ucount'] >= $cfg['ucount'])
			$error[$i++] = sprintf($T['err']['update count'], $cfg['ucount']);

		// **** Remove Doubles ($data already in the db) & create SQL query as we check input
		$sql_query = "UPDATE users SET ";

		//
		// Verify input $data

		// Name validity
		if (trim($data['name']) AND $data['name'] != $personaldata['name']) {
			if (!eregi($rx['name'],$data['name']))
				$error[$i++] = $T['err']['user']['name'];

			$sql_query .= "name='".addslashes($data['name'])."', ";
		}

		// Username validity
		if (trim($data['username'])) $data['username'] = strtolower($data['username']);
		if (trim($data['username']) AND $data['username'] != $personaldata['username'])	{
			if (eregi($rx['user'],$data['username'])) {
				$dbp = mysql_query("SELECT username FROM users WHERE username = '".$data['username']."' AND id = '".$data['id']."'");
				if (mysql_num_rows($dbp))
					$error[$i++] = $T['err']['user']['used username'];

				// Check if no alias is set for that username
				$dbp = mysql_query("SELECT username FROM users WHERE aliases LIKE '% ".$data['username']." %' AND id = '".$personaldata['id']."'");
				if (mysql_num_rows($dbp))
					$error[$i++] = $T['err']['user']['aliases'].$data['username'];

				// Move all properties over
				mysql_query('UPDATE `properties` SET `user` = "'.$data['username'].'" WHERE `user` = "'.$personaldata['username'].'" AND `id` = "'.$data['id'].'"');
			} else
				$error[$i++] = $T['err']['user']['username'];

			$sql_query .= "username='".$data['username']."', ";
		}

		// Password
		if (trim($data['password']) AND $data['password'] != $personaldata['password'])	{
			if ($data['pass_confirm']) {
				if (!eregi($rx['pass'],$data['password'])) $error[$i++] = $T['err']['user']['password'];
				if ($cfg['strong_passwords'])
					if (!password_check($data['password'])) $error[$i++] = $T['err']['user']['weakpassword'];
				// Escape ' and " for MySQL.
				$data['password'] = addslashes($data['password']);

				$sql_query .= "password=ENCODE('".$data['password']."','".$cfg['key']."'), ";
			}
		}

		// User Root Validity
		if (isset($data['root'])) {
			$dir = ereg_replace("^/","",str_replace("../","",$data['root']));
			$dir = $cfg['webdir']."/".$personaldata['id']."/".$dir;
			$data['root'] = ereg_replace("/$","",$dir);
			// we don't want roots with ' or " in them and it must exist
			if (strstr($data['root'],"\"") OR strstr($data['root'],"'") OR !@is_dir($data['root']))
				$error[$i++] = $T['err']['user']['root'].$data['root'];

			if ($data['root'] != $personaldata['root'])
				$sql_query .= "root='".$data['root']."', ";
		}

		// Verify User Level
		if (isset($data['level']) AND $data['level'] != $personaldata['level']) {
			$data['level'] = intval($data['level']);
			if ($data['level'] < $userdata['level'])
				$error[$i++] = $T['err']['user']['level'];

			$sql_query .= "level='".$data['level']."', ";
		}



		// Verify HD availability
		if (isset($data['hd']) AND $data['hd'] != $personaldata['hd']) {
			$data['hd'] = intval($data['hd']);
			if ($dom_data['hd'] < $data['hd'] && $dom_data['hd'] != -1)
				$error[$i++] = $T['err']['user']['hd'].$dom_data['hd'];

			$sql_query .= "hd='".$data['hd']."', ";
		}

		// Verify Shell
		if (isset($data['shell']) AND $data['shell'] != $personaldata['shell']) {
			if ($data['shell'] == "on") {
				if ($dom_data['shell'] != "on") {
					$error[$i++] = $T['err']['user']['shell'];
					$data['shell'] = "off";
				}
			}
			else $data['shell'] = "off";

			$sql_query .= "shell='".$data['shell']."', ";
		}

		// Set User's Language
		if (isset($data['lang']) AND $data['lang'] != $personaldata['lang']) {
			if (!ereg($rx['word'],$data['lang']) OR !file_exists("lang/".$data['lang'].".phps"))
				$data['lang'] = $cfg['defaultlang'];

			$sql_query .= "lang='".$data['lang']."', ";
		}
		// Set User's web-cp skin
		if (isset($data['skin']) AND $data['skin'] != $personaldata['skin']) {
			if (!ereg($rx['alnum'],$data['skin']) OR !file_exists("skin/".$data['skin']))
				$data['skin'] = $cfg['defaultskin'];

			$sql_query .= "skin='".$data['skin']."', ";
		}

		// E-Mail Forwarding
		if (isset($data['forward'])) {
			$forward = trim(ereg_replace("[;,]"," ",$data['forward']));
			$forward = split("[[:space:]]+",$forward);
			if (is_array($forward) AND trim($data['forward'])) {
				do {
					// is it not valid?
					if (!eregi($rx['eml'],current($forward)) AND !eregi($rx['user'],current($forward)))
						$error[$i++] = $T['err']['user']['forward'].current($forward);
				} while(next($forward));

				// Reset $data['forward'] to a correct value.
				$data['forward'] = trim(implode(" ",$forward));

				if ($data['forward'] != $personaldata['forward'])
					$sql_query .= "forward='".$data['forward']."', ";
			}
			elseif ($data['forward'] != $personaldata['forward'])
				$sql_query .= "forward='', ";
		}

		// Aliases validity, unique
		if (isset($data['aliases'])) {
			$aliases = trim(ereg_replace("[;,]"," ",strtolower($data['aliases'])));
			$aliases = split("[[:space:]]+",$aliases);
			if (is_array($aliases) AND $data['aliases']) {
				$rmalias = '';
				do {
					// is it valid?
					if (eregi($rx['alias'],current($aliases))) {
						// verify if its not used as a user already
						$dbp = mysql_query("SELECT username FROM users WHERE username = '".current($aliases)."' AND id = '".$personaldata['id']."' AND username != '".$data['uid']."'");
						if (mysql_num_rows($dbp))
							$error[$i++] = $T['err']['user']['aliases'].current($aliases);

						// verify if its not used as an alias already
						$dbp = mysql_query("SELECT username FROM users WHERE aliases LIKE '% ".current($aliases)." %' AND id = '".$personaldata['id']."' AND username != '".$data['uid']."'");
						if (mysql_num_rows($dbp))
							$error[$i++] = $T['err']['user']['aliases'].current($aliases);

						if (current($aliases) == $personaldata['username'])
							$rmalias = current($aliases);

					}
					// not valid
					else
						$error[$i++] = $T['err']['user']['aliases'].current($aliases);
				} while(next($aliases));

				// Reset $data['aliases'] to a correct value.  The trailing spaces are needed for fast searching (step above)
				$data['aliases'] = " ".trim(implode(" ",$aliases))." ";
				if ($rmalias)
					str_replace(" $rmalias ", " ",$data['aliases']);
				$data['aliases'] = ereg_replace("[[:space:]]+"," ",$data['aliases']);

			}
			elseif ($data['aliases']) {
				if (!eregi($rx['alias'],$data['aliases']))
					$error[$i++] = $T['err']['user']['aliases'].$data['aliases'];
				else {
					// verify if its not used as a user already
					$dbp = mysql_query("SELECT username FROM users WHERE username = '".$data['aliases']."' AND id = '".$personaldata['id']."' AND username != '".$data['uid']."'");
					if (mysql_num_rows($dbp))
						$error[$i++] = $T['err']['user']['aliases'].$data['aliases'];

					// verify if its not used as an alias already
					$dbp = mysql_query("SELECT username FROM users WHERE aliases LIKE '% ".$data['aliases']." %' AND id = '".$personaldata['id']."' AND username != '".$data['uid']."'");
					if (mysql_num_rows($dbp))
						$error[$i++] = $T['err']['user']['aliases'].$data['aliases'];
				}
			}
			if ($data['aliases'] != $personaldata['aliases'])
				$sql_query .= "aliases='".$data['aliases']."', ";
		}

		// Catch-All
		if (isset($data['catchall']) AND $data['catchall'] != $personaldata['catchall']) {
			if ($data['catchall'] == "true") {
				$dbp = mysql_query("SELECT username FROM users WHERE catchall = 'true' AND id = '".$personaldata['id']."' AND username != '".$data['uid']."'");
					if ($tmp = mysql_fetch_array($dbp))
						$error[$i++] = $T['err']['user']['catchall'].$tmp['username'];

				$sql_query .= "catchall='true', ";
			}
			else
				$sql_query .= "catchall='false', ";
		}

		// Autoresponder Check
		if (isset($data['autoreply']) AND $data['autoreply'] != $personaldata['autoreply']) {
			$data['autoreply'] = addslashes($data['autoreply']);
			$sql_query .= "autoreply='".$data['autoreply']."', ";
		}

		// IP Restriction Check
		if (isset($data['ip_restrict']) AND $data['ip_restrict'] != $personaldata['ip_restrict']) {
			if (!ereg("^".$data['ip_restrict'],$_SERVER['REMOTE_ADDR']))
				$error[$i++] = $T['err']['user']['ip_restrict'];
			$sql_query .= "ip_restrict='".$data['ip_restrict']."', ";
		}

		// Make sure we are not overwriting something:
		if ($personaldata['action'])
			$tmpaction = $personaldata['action'];
		else
			$tmpaction = 'update';

		//
		// Update Database

		if ($sql_query == "UPDATE users SET ") $error[$i++] = $T['err']['nothing to update'];
		else $sql_query .= "action='$tmpaction' WHERE username = '".$data['uid']."' AND id = '".$data['id']."'";
		// If any error occured before, return it now
		if (is_array($error)) return $error;
		else {
			// Execute the db query
			mysql_query($sql_query);
			// create md5 signature and insert it.
			if (trim($data['username']))
				$userid = $data['username'];
			else
				$userid = $data['uid'];

			$hash = fetchdata("*","user",array($userid, $data['id']));
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE users SET hash='$hash', ucount = ucount + 1 WHERE username = '$userid' AND id = '".$data['id']."'");

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"user updated: $userid",$_SERVER['REMOTE_ADDR']);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
	// end 'update'
	///

	//
	// Suspend an user entry in the database
	elseif ($action == "suspend") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain group id
		//
		//
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[username]	username

		// fetch some useful data
		$pdata = mysql_query("SELECT level FROM users WHERE username = '".$data['username']."' AND id='".$data['id']."'");
		$personaldata = mysql_fetch_array($pdata);

		// Check update count
		if ($personaldata['ucount'] >= $cfg['ucount'])
			$error[$i++] = sprintf($T['err']['update count'], $cfg['ucount']);

		// Error if the user tries to suspend himself
		if ($data['username'] == $userdata['username'])
			$error[$i++] = $T['err']['user']['suspend myself'];

		// Username validity
		if (!eregi($rx['user'],$data['username']))
			$error[$i++] = $T['err']['user']['username'];

		if ($userdata['level'] > $personaldata['level']) {
			$error[1] = $T['err']['user higher'];
			return $error;
		}

		// If any error occured before, return it now
		if (is_array($error)) return $error;
		else {
			// Execute the db query
			mysql_query("UPDATE users SET action='suspend' WHERE username = '".$data['username']."' AND id='".$data['id']."'");

			// create md5 signature and insert it.
			$hash = fetchdata("*","user",Array($data['username'], $data['id']));
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE users SET hash='$hash' WHERE username = '".$data['username']."' AND id='".$data['id']."'");

			// update ucount
			mysql_query("UPDATE domains SET ucount = ucount + 1 WHERE domain = '".$data['domain']."'");
			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"user suspended: ".$data['username'],$_SERVER['REMOTE_ADDR']);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
	// end 'suspend'
	///

	//
	// Unsuspend an user entry in the database
	elseif ($action == "unsuspend") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain group id
		//
		//
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[username]	username
		// Username validity
		if (!eregi($rx['user'],$data['username']))
			$error[$i++] = $T['err']['user']['username'];

		// If any error occured before, return it now
		if (is_array($error)) return $error;
		else {
			// Execute the db query
			mysql_query("UPDATE users SET action='unsuspend',time='NOW()' WHERE username = '".$data['username']."' AND id='".$data['id']."'");

			// create md5 signature and insert it.
			$hash = fetchdata("*","user",Array($data['username'], $data['id']));
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE users SET hash='$hash' WHERE username = '".$data['username']."' AND id='".$data['id']."'");

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"user unsuspended: ".$data['username'],$_SERVER['REMOTE_ADDR']);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
	// end 'unsuspend'
	///

	//
	// Mark an user to be removed
	elseif ($action == "remove") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain group id
		//
		//
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[username]	username
		// Error if the user tries to remove himself
		if ($data['username'] == $userdata['username'])
			$error[$i++] = $T['err']['user']['remove myself'];

		// Username validity
		if (!eregi($rx['user'],$data['username']))
			$error[$i++] = $T['err']['user']['username'];

		// If any error occured before, return it now
		if (is_array($error)) return $error;
		else {
			// Execute the db query
			mysql_query("UPDATE users SET action='remove' WHERE username = '".$data['username']."' AND id = '".$data['id']."'");
			mysql_query("DELETE FROM crons WHERE user = '".$data['username']."'");
			// create md5 signature and insert it.
			$hash = fetchdata("*","user",array($data['username'], $data['id']));
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE users SET hash='$hash' WHERE username = '".$data['username']."' AND id='".$data['id']."'");

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"user suspended: ".$data['username'],$_SERVER['REMOTE_ADDR']);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
}


// Function:	domain()
// Utility:	Create, Delete, Modify, Suspend, Unsuspend domainss; make sure everything is ok & secure
// Usage:	domain(ACTION,DATA,RETURN)
// Examples:	domain("create",$_POST);
//		domain("delete",$domain_id);
// Return:	$error		array var or nothing
// Definitions:	ACTION:		create, delete, modify, suspend, unsupend
//		DATA:		domain ID number, HTTP_POST_VARS, etc
// 		RETURN:		returns domain ID
function domain($action,$data,&$return) {
	// Get configurations, userdata, Language file, regex
	GLOBAL $userdata, $cfg, $T, $rx;

	$error = Array();

	// kill demo users (return error)
	if ($userdata['type'] == "demo") {
		$error[1] = $T['err']['demo user'];
		return $error;
	}
	// Set error 'counter'
	$i = 1;

	// Reset return val
	$return = '';

	//
	// Create a new domain entry in the database
	if ($action == "create") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* reseller group id that will hold the domain [OR] domain id that hold a sub/pointer
		// data[type]		*REQUIRED* type of domain: domain,subdomain,pointer
		//
		//
		// Expected Input Data (from POST)
		// ===============================
		// * Optional
		// data[ip_addr]	IP Address, dedicated or shared.
		// data[path]		* Path to domain pointer
		// data[hostname]	Hostname (www)
		// data[domain]		Domain name (domain.com)
		// data[aliases]	* Hostname aliases; seperated by space, coma or new lines
		// data[catchall]	* Catch *.domain.com, removes all aliases, requires no sub-domains and will stop them.
		// data[nohost]		* Catch http://domain.com
		// data[redirect]	* Redirect *.domain.com or domain.com to [hostname].[domain] (to use with 2 opt. above)

		// data[email]		Domain Contact E-Mail Address
		// data[users]		* Number of users allowed
		// data[hd]		* HD Quota
		// data[subdomains]	* Number of subdomains allowed
		// data[pointers]	* Number of domain pointers allowed
		// data[databases]	* # Databases allowed.
		// data[serverside][x]	* Server Side languages. [x] is what's defined by $cfg['sslang'], cam be: on, off, na, ask
		// data[defaultroot]	* Default Domain's user root dir. Replaces %USER% by username
		// data[httpcustom]	* Custom Apache commands to be inserted at the end of the domain's config
		// Get some reseller data
		$id = substr($data['id'], 0, 5);
		$resellerdata = fetchdata("*","reseller",$id);
		$users = fetchdata("users","total",$id);
		$domains = fetchdata("domains","total",$id);
		$pointers = fetchdata("pointers","alloc",$id);
		$subdomains = fetchdata("subdomains","alloc",$id);
		$databases = fetchdata("databases","total",$id);
		$hd = fetchdata("hd","alloc",$id);

		// create unique 10 decimal ID, 5 from reseller, 5 random
		mt_srand((double)microtime()*1000000);
   		do
   			$num = mt_rand(10001,99999);
   		while (fetchdata("id","domain",$id.$num));
   		$num = $id.$num;
   		
   		

	if (is_array($data['ip_addr'])) {
	foreach($data['ip_addr'] as $key => $val) {
		// IP Address validity
		if (eregi($rx['ip'],$val)) {
			// check if it is in the reseller's ip pool
			if (!strstr(' '.$resellerdata['ip'].' ',' '.$val.' '))
				$error[$i++] = $T['err']['domain']['ip address'];
		}
		else
			$error[$i++] = $T['err']['domain']['ip address'];

				// Set IP priority if this IP is unused
		$dbp = mysql_query("SELECT id FROM domains WHERE ip = '".$data['ip_addr']."'");
		if (!mysql_num_rows($dbp))
			$ippriority[] = 0;
		else
			$ippriority[] = 1;

	} //end foreach

		$data['ip_addr'] = implode('|',$data['ip_addr']);
		$ippriority = implode('|',$ippriority);

	//else if it's not an array do the following:
	} else {

		if (eregi($rx['ip'],$data['ip_addr'])) {
			// check if it is in the reseller's ip pool
			if (!strstr(' '.$resellerdata['ip'].' ',' '.$data['ip_addr'].' '))
				$error[$i++] = $T['err']['domain']['ip address'];
		}
		else
			$error[$i++] = $T['err']['domain']['ip address'];

				// Set IP priority if this IP is unused
		$dbp = mysql_query("SELECT id FROM domains WHERE ip = '".$data['ip_addr']."'");
		if (!mysql_num_rows($dbp))
			$ippriority = 0;
		else
			$ippriority = 1;

	}
		// Hostname validity
		$data['hostname'] = strtolower($data['hostname']);
		if (!ereg($rx['host'],$data['hostname']))
			$error[$i++] = $T['err']['domain']['hostname'];

		// Domain validity
		$data['domain'] = strtolower($data['domain']);
		if (!ereg($rx['dom'],$data['domain']))
			$error[$i++] = $T['err']['domain']['domain'];

		// E-Mail validity
		if (!eregi($rx['eml'],$data['email']))
			$error[$i++] = $T['err']['domain']['email'];

		// Check domain type & if its unique
		if ($data['type'] == "domain") {
			// Is this domain already taken?
			$dbp = mysql_query("SELECT id FROM domains WHERE domain = '".$data['domain']."'");
			if (mysql_num_rows($dbp)){
                            unset($dbp);
                            $dbp = mysql_query("SELECT id FROM domains WHERE domain = '".$data['domain']."' AND host = '".$data['hostname']."'");
			if (mysql_num_rows($dbp))
				$error[$i++] = $T['err']['domain']['domain taken'];
                                else
                                    $data['sub']='true';
                        }else $data['sub']='false';
		}
		elseif ($data['type'] == "subdomain") {
			if ($data['id'] < 1000000000)
				$error[$i++] = $T['err']['domain']['invalid type'];
			// Is this subdomain already taken?
			$dbp = mysql_query("SELECT id FROM domains WHERE host = '".$data['hostname']."' AND domain = '".$data['domain']."'");
			if (mysql_num_rows($dbp))
				$error[$i++] = $T['err']['domain']['domain taken'];
		}
		elseif ($data['type'] == "pointer") {
			if ($data['id'] < 1000000000)
				$error[$i++] = $T['err']['domain']['invalid type'];
			// Is this domain already taken?
			$dbp = mysql_query("SELECT id FROM domains WHERE host = '".$data['hostname']."' AND domain = '".$data['domain']."'");
			if (mysql_num_rows($dbp))
				$error[$i++] = $T['err']['domain']['domain taken'];
			else {
				// Cancel nohost, wildcard and redirect if there are more than one site under that domain
				$dbp = mysql_query("SELECT id,owner FROM domains WHERE domain = '".$data['domain']."'");
				if ($tmp = mysql_fetch_array($dbp)) {
					$data['catchall'] = "false";
					$data['nohost'] = "false";
					$data['redirect'] = "false";
					// Check if its under a domain we control
					if ($tmp['owner'] != $data['id'] AND $tmp['id'] != $data['id'])
						$error[$i++] = $T['err']['domain']['domain taken'];
				}
			}
		}
		else
			$error[$i++] = $T['err']['domain']['invalid type'];
		// Check update count
		$dbp = mysql_query("SELECT ucount FROM domains WHERE domain='".$data['domain']."'");
		$ucount = mysql_fetch_array($dbp);
		if ($ucount['ucount'] >= $cfg['ucount'])
			$error[$i++] = sprintf($T['err']['update count'], $cfg['ucount']);
		// Check path if its a domain pointer
		if ($data['type'] == "pointer") {
                        // Check if it's a remote pointer
                        if($data['remote']==""){
			$data['path'] = ereg_replace("^/","",$data['path']);
			$data['path'] = ereg_replace("/$","",$data['path']);
			$dir = $cfg['webdir']."/".$data['id']."/".$data['path'];
			if (@!is_dir($dir))
				$error[$i++] = $T['err']['domain']['invalid path'];
			$data['path'] = $dir;
                        }else $data['path']=$data['remote'];
		}
		else $data['path'] = $cfg['webdir']."/$num";

		// Do we have a wildcard?
		if ($data['catchall'] == "true" AND $data['type'] != "subdomain") {
			// Remove other aliases
			$data['aliases'] = "";
		}
		else $data['catchall'] = "false";

		// Check no host and domain redirect
		if ($data['nohost'] == "true") {
			if ($data['redirect'] != "true") $data['redirect'] = "false";
		}
		else {
			$data['nohost']= "false";
			$data['redirect'] = "false";
		}
		// Aliases validity, unique
		if ($data['aliases']) {
			$aliases = trim(ereg_replace("[;,]"," ",$data['aliases']));
			$aliases = split("[[:space:]]+",$aliases);
			if (is_array($aliases) AND trim($data['aliases'])) {
				do {
					// is it valid?
					if (eregi($rx['host'],current($aliases))) {
						// It must not be the same as our main host!
						if (current($aliases) == $data['hostname'])
							$error[$i++] = $T['err']['domain']['aliases'].current($aliases);

						// verify if its not used already
						$dbp = mysql_query("SELECT id FROM domains WHERE (host = '".current($aliases)."' OR aliases LIKE '% ".current($aliases)." %') AND domain = '".$data['domain']."'");
						if (mysql_num_rows($dbp))
							$error[$i++] = $T['err']['domain']['aliases'].current($aliases);

					}
					// not valid
					else
						$error[$i++] = $T['err']['domain']['aliases'].current($aliases);
				} while(next($aliases));

				// Reset $data['aliases'] to a correct value.  The trailing spaces are needed for fast searching (step above)
				$data['aliases'] = " ".trim(implode(" ",$aliases))." ";
				$data['aliases'] = ereg_replace("[[:space:]]+"," ",$data['aliases']);
			}
			// there is no aliases, unset it.
			else
				unset($data['aliases']);
		}

		// Check Server Sides (PHP, ASP, SSI, SSL, CGI/Perl, Python, etc.)
		// get list from config first.
		if (strstr($cfg['sslang'],",")) $sslang = explode(",",$cfg['sslang']);
		else $sslang[0] = $cfg['sslang'];

		$tmpdata = array();
		if($data['type']=='subdomain' || $data['type']=='pointer')
			$parentss = fetchdata('serverside', 'domain', $data['id']);
		else
			$parentss = array();

		foreach($sslang as $ss) {
			$ss = trim($ss);
			$domainss = $data['serverside'][$ss];
			if($domainss=='on' || $domainss=='off') {
				if(isset($parentss['serverside'][$ss]) && $parentss['serverside'][$ss]!='on'
				   && $parentss['serverside'][$ss]!= 'off')
					$tmpdata[$ss] = 'na';
				elseif($resellerdata['serverside'][$ss] == 'on')
					$tmpdata[$ss] = $domainss;
				else
					$tmpdata[$ss] = 'na';

			} else
				$tmpdata[$ss] = 'na';
		}

		$data['serverside'] = addslashes(serialize($tmpdata));

		/*$j = 0;
		unset($tmpdata);
		while ($sslang[$j]) {
			$tmp = $data['serverside'][trim($sslang[$j])];
			if ($tmp == "on" OR $tmp == "off" OR $tmp == "ask") {
				if ($resellerdata['serverside'][trim($sslang[$j])] == "on")
					$tmpdata[trim($sslang[$j])] = $tmp;
				else
					$tmpdata[trim($sslang[$j])] = "na";
			}
			else
				$tmpdata[trim($sslang[$j])] = "na";
			++$j;
		}
		$data['serverside'] = addslashes(serialize($tmpdata));*/

		// Verify Shell
		if ($data['shell'] == "on" OR $data['shell'] == "off" OR $data['shell'] == "ask") {
			if ($resellerdata['shell'] != "on")
				$data['shell'] = "off";
		} else {
			$data['shell'] = "off";
		}

		// HTTP custom check: only for serveradmin+
		if ($data['httpcustom'] AND $userdata['level'] > 1) $data['httpcustom'] = "";
		else $data['httpcustom'] = addslashes($data['httpcustom']);

		// Check if enough domain, subdomains, pointers, users, hd space are availabe. Validate ['defaultroot'].
		if ($data['type'] == "domain") {
			// domain check
			$total = $resellerdata['domains'];
			$used = $domains['domains'];
			if (($total - $used) < 1 && ($total != -1)) $error[$i++] = $T['err']['domain']['no domains'];
			// users
			$data['users'] = intval($data['users']);
			$total = $resellerdata['users'];
			$used = $users['users'];
			if (($total - $used) < $data['users'] && ($total != -1)) $error[$i++] = $T['err']['domain']['no users'].intval($total - $used);
			if ($data['users'] == 0) $error[$i++] = $T['err']['domain']['need user'];

			// subdomains
			$data['subdomains'] = intval($data['subdomains']);
			$total = $resellerdata['subdomains'];
			$used = $subdomains['subdomains'];
			if (($total - $used) < $data['subdomains'] && ($total != -1)) $error[$i++] = $T['err']['domain']['no subdomains'].intval($total - $used);

			// pointers
			$data['pointers'] = intval($data['pointers']);
			$total = $resellerdata['pointers'];
			$used = $pointers['pointers'];
			if (($total - $used) < $data['pointers'] && ($total != -1)) $error[$i++] = $T['err']['domain']['no pointers'].intval($total - $used);

			// hd space
			$data['hd'] = intval($data['hd']);
			$total = $resellerdata['hd'];
			$used = $hd['hd'];
			if (($total - $used) < $data['hd'] && ($total != -1)) $error[$i++] = $T['err']['domain']['no hd'].intval($total - $used);
			if ($data['hd'] == 0) $error[$i++] = $T['err']['domain']['need hd'].intval($total - $used);


			// databases
			$data['databases'] = intval($data['databases']);
			$total = $resellerdata['db'];
			$used = $databases['databases'];
			if (($total - $used) < $data['databases'] && ($total != -1)) $error[$i++] = $T['err']['domain']['no databases'].intval($total - $used);

			// default user root
			if ($data['defaultroot']) {
				unset($root);
				if (stristr($data['defaultroot'],"%USER%")) {
					$root = explode("%USER%",$data['defaultroot']);
					$defroot = $root[0];
					// make sure the user is created within /www/web or /www/data or /www/users
                                        $tdefroot="/".$data['hostname'].$defroot;
                                        $twebroot="/".$data['hostname']."/".$cfg['webname']."/";
                                        $tdataroot= "/".$data['hostname']."/data/";
                                        $tuserroot= "/".$data['hostname']."/users/";

                                        if (($tdefroot != $twebroot) AND ($tdefroot != $tdataroot) AND ($tdefroot != $tuserroot)) $error[$i++] = $T['err']['domain']['invalid user path'];

				}
				else
					$defroot = $data['defaultroot'];

				$defroot = ereg_replace("^/","",$defroot);

				// construct real path
                                $dir = $cfg['webdir']."/$num/".$data['hostname']."/".$defroot;

				if ($root)
					$data['defaultroot'] = $dir."%USER%".$root[1];
				else
					$data['defaultroot'] = $dir;
			}



		}
		else {
			$domdata = fetchdata("subdomains,pointers","domain",$data['id']);

			if ($data['type'] == 'subdomain') {
				$total = fetchdata("subdomains","total",$data['id']);
				if ($domdata['subdomains'] <= $total['subdomains'] && $domdata['subdomains'] != -1)
					$error[$i++] = $T['err']['domain']['no subdomain'];
			}
			if ($data['type'] == 'pointer') {
				$total = fetchdata("pointers","total",$data['id']);
				if ($domdata['pointers'] <= $total['pointers'] && $domdata['pointers'] != -1)
					$error[$i++] = $T['err']['domain']['no pointer'];
			}

			$data['users'] = 0;
			$data['subdomains'] = 0;
			$data['databases'] = 0;
			$data['pointers'] = 0;
			$data['users'] = 0;
			$data['hd'] = 0;
			$data['defaultroot'] = "";
		}

		$hook_err = Array();
		$hook_err = call_hook('web:domain:'.$action.':check', $data);
		foreach($hook_err as $herr) {
			if ($herr['error'] != '') {
				$error[$i++] = $herr['error'];

			}
			if ($herr['change'] == 'change') {
				$hook_change = true;
			}
		}


		//
		// Insert into Database
		// If any error occured before, return it now
		if (!empty($error)) return $error;
		else {
			$SQL = "INSERT INTO domains SET id=$num, owner=".$data['id'].", priority=$ippriority, ip='".$data['ip_addr']."',host='".$data['hostname']."',
				host1='".$data['hostname']."', domain='".$data['domain']."', domain1='".$data['domain']."', aliases='".$data['aliases']."',
				catchall='".$data['catchall']."', nohost='".$data['nohost']."', redirect='".$data['redirect']."', path='".$data['path']."',
				defaultroot='".$data['defaultroot']."', type='".$data['type']."', hd='".$data['hd']."', users='".$data['users']."',
				subdomains='".$data['subdomains']."', pointers='".$data['pointers']."',	serverside='".$data['serverside']."',
				db='".$data['databases']."', shell='".$data['shell']."', email='".$data['email']."',
				httpcustom='".$data['httpcustom']."', action='create', dns='".$data['dnsentry']."', sub='".$data['sub']."', sdmail='".$data['sdmail']."'";
			mysql_query($SQL);

			// create md5 signature and insert it.
			$hash = fetchdata("*","domain",$num);
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE domains SET hash='$hash' WHERE id = '$num'");
			// update ucount
			mysql_query("UPDATE domains SET ucount = ucount + 1 WHERE domain = '".$data['domain']."'");
			// Return ID in $return
			$return = $num;

			$data['id'] = $return;
			call_hook('web:domain:'.$action, $data);

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"domain created: ".$data['hostname'].".".$data['domain'],$_SERVER['REMOTE_ADDR'].': '.$SQL);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
	// end 'create'
	///

	//
	// Update a domain entry in the database
	elseif ($action == "update") {

		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain/sub/pointer id
		//
		//
		// Expected Input Data (from POST)
		// ===============================
		// All Optional
		// data[ip_addr]	IP Address, dedicated or shared.
		// data[path]		Path to domain pointer
		// data[hostname]	Hostname (www)
		// data[domain]		Domain name (domain.com)
		// data[aliases]	Hostname aliases; seperated by space, coma or new lines
		// data[catchall]	Catch *.domain.com, removes all aliases, requires no sub-domains and will stop them.
		// data[nohost]		Catch http://domain.com
		// data[redirect]	Redirect *.domain.com or domain.com to [hostname].[domain] (to use with 2 opt. above)
		// data[priority]	Domain IP Priority (first or not) true or false
		// data[email]		Domain Contact E-Mail Address
		// data[users]		Number of users allowed
		// data[hd]		HD Quota
		// data[subdomains]	Number of subdomains allowed
		// data[pointers]	Number of domain pointers allowed
		// data[databases]	# Databases allowed.
		// data[serverside][x]	Server Side languages. [x] is what's defined by $cfg['sslang'], cam be: on, off, na, ask
		// data[defaultroot]	Default Domain's user root dir. Replaces %USER% by username
		// data[ip_restrict]	IP restriction on the account.  Can match all or part of an IP Address.
		// data[httpcustom]	Custom Apache commands to be inserted at the end of the domain's config
		// Get some domain & reseller data
		$id = substr($data['id'], 0, 5);
		$resellerdata = fetchdata("*","reseller",$id);
		$domaindata = fetchdata("*","domain",$data['id']);

		// Get current reseller usage for validation
		$users = fetchdata("users","alloc",$id);
		$pointers = fetchdata("pointers","alloc",$id);
		$subdomains = fetchdata("subdomains","alloc",$id);
		$databases = fetchdata("databases","alloc",$id);
		$hd = fetchdata("hd","alloc",$id);

		// Check update count
		$dbp = mysql_query("SELECT ucount FROM domains WHERE domain='".$domaindata['domain']."'");
		$ucount = mysql_fetch_array($dbp);
		if ($ucount['ucount'] >= $cfg['ucount'])
			$error[$i++] = sprintf($T['err']['update count'], $cfg['ucount']);

		// **** Remove Doubles ($data already in the db) & create SQL query as we check input
		$sql_query = "UPDATE domains SET ";

		//
		// Verify input $data

		if (is_array($data['ip_addr'])) {
			foreach($data['ip_addr'] as $key => $val) {
				// IP Address validity
				if (eregi($rx['ip'],$val)) {
					// check if it is in the reseller's ip pool
					if (!strstr(' '.$resellerdata['ip'].' ',' '.$val.' '))
						$error[$i++] = $T['err']['domain']['ip address'];
				}
				else
					$error[$i++] = $T['err']['domain']['ip address'];

			}

			$data['ip_addr_str'] = implode('|',$data['ip_addr']);

			if (trim($data['ip_addr_str']) AND $data['ip_addr_str'] != $domaindata['ip']) {
				$sql_query .= "ip='".$data['ip_addr_str']."', ";
			}

		} else {

			if (trim($data['ip_addr']) AND $data['ip_addr'] != $domaindata['ip']) {
				if (eregi($rx['ip'],$data['ip_addr'])) {
					// check if it is in the reseller's ip pool
					if (!strstr(' '.$resellerdata['ip'].' ',' '.$data['ip_addr'].' '))
						$error[$i++] = $T['err']['domain']['ip address'];
				}
				else
					$error[$i++] = $T['err']['domain']['ip address'];

				$sql_query .= "ip='".$data['ip_addr']."', ";
			}
		}
		// Hostname validity
		if (trim($data['hostname']) AND $data['hostname'] != $domaindata['host']) {
			$data['hostname'] = strtolower($data['hostname']);
			if (!ereg($rx['host'],$data['hostname']))
				$error[$i++] = $T['err']['domain']['hostname'];

			$sql_query .= "host='".$data['hostname']."', ";
		}

		// Domain validity
		if (trim($data['domain']) AND $data['domain'] != $domaindata['domain']) {
			$data['domain'] = strtolower($data['domain']);
			if (ereg($rx['dom'],$data['domain'])) {
				if ($domaindata['type'] == "domain") {
					// Is this domain already taken?
					$dbp = mysql_query("SELECT id FROM domains WHERE domain = '".$data['domain']."'");
					if (mysql_num_rows($dbp))
						$error[$i++] = $T['err']['domain']['domain taken'];
				}
				elseif ($domaindata['type'] == "pointer") {
					// Is this domain already taken?
					$dbp = mysql_query("SELECT id FROM domains WHERE host = '".$data['hostname']."' AND domain = '".$data['domain']."'");
					if (mysql_num_rows($dbp))
						$error[$i++] = $T['err']['domain']['domain taken'];
					else {
						// Cancel nohost, wildcard and redirect if there are more than one site under that domain
						$dbp = mysql_query("SELECT id,owner FROM domains WHERE domain = '".$data['domain']."'");
						if ($tmp = mysql_fetch_array($dbp)) {
							$data['catchall'] = "false";
							$data['nohost'] = "false";
							$data['redirect'] = "false";
							// Check if its under a domain we control
							if ($tmp['owner'] != $domaindata['owner'] AND $tmp['id'] != $domaindata['owner'])
								$error[$i++] = $T['err']['domain']['domain taken'];
						}
					}
				}
				else
					$data['domain'] = $domaindata['domain'];

			} else
				$error[$i++] = $T['err']['domain']['domain'];

			$sql_query .= "domain='".$data['domain']."', ";
		}

		// Domain Priority validity
		if (trim($data['priority'])) {
			if ($data['priority'] == "false") $data['priority'] = 0;
			else $data['priority'] = 1;

			if ($data['priority'] != $domaindata['priority']) {

				if ($data['priority'] == 1) {
					// Check if another domain has priority already, if so error.
					$dbp = mysql_query("SELECT host,domain FROM domains WHERE ip='".$data['ip_addr']."' AND priority=1");
					if ($tmp = mysql_fetch_array($dbp))
						$error[$i++] = $T['err']['domain']['priority'].' '.$tmp['host'].'.'.$tmp['domain'];
				}
				$sql_query .= "priority='".$data['priority']."', ";
			}
		}

		// E-Mail contact validity
		if (trim($data['email']) AND $data['email'] != $domaindata['email']) {
			if (!eregi($rx['eml'],$data['email']))
				$error[$i++] = $T['err']['domain']['email'];

			$sql_query .= "email='".$data['email']."', ";
		}

		// Check path if its a domain pointer
		if (trim($data['path']) AND $data['path'] != $domaindata['path']) {
			if ($domaindata['type'] == "pointer") {
                            // Check if it's a remote pointer
                            if($data['remote']==""){
				$data['path'] = ereg_replace("^/","",$data['path']);
				$data['path'] = ereg_replace("/$","",$data['path']);
				$dir = $cfg['webdir']."/".$domaindata['owner']."/".$data['path'];
				if (@!is_dir($dir))
					$error[$i++] = $T['err']['domain']['invalid path'];
				$sql_query .= "path='".$dir."', ";
                            }else $sql_query.="path='".$data['remote']."', ";
			}
		}

		// Do we have a wildcard?
		if (trim($data['catchall']) AND $data['catchall'] != $domaindata['catchall']) {
			if ($domaindata['type'] != "subdomain") {
				// Remove other aliases
				$data['aliases'] = "";

				if ($data['catchall'] == "true" OR $data['catchall'] == "false")
					$sql_query .= "catchall='".$data['catchall']."', ";
			}
		}

		// Check no host and domain redirect
		if (trim($data['nohost']) AND $data['nohost'] != $domaindata['nohost']) {
			if ($data['nohost'] == "true" OR $data['nohost'] == "false")
				$sql_query .= "nohost='".$data['nohost']."', ";
		}
		if ($data['nohost'] == "false") $data['redirect'] = "false";
		if (trim($data['redirect']) AND $data['redirect'] != $domaindata['redirect']) {
			if ($data['redirect'] == "true" OR $data['redirect'] == "false")
				$sql_query .= "redirect='".$data['redirect']."', ";
		}


		// Aliases validity, unique
		if (isset($data['aliases']) AND $data['aliases'] != $domaindata['aliases']) {
			if ($data['aliases']) {
				$aliases = split("([[:space:]]+,?|[[:space:]]*,)",$data['aliases']);
				if (is_array($aliases)) {
					do {
						// is it valid?
						if (eregi($rx['host'],current($aliases))) {
							// It must not be the same as our main host!
							if (current($aliases) == $data['hostname'])
								$error[$i++] = $T['err']['domain']['aliases'].current($aliases);

							// verify if its not used already
							$dbp = mysql_query("SELECT id FROM domains WHERE (host = '".current($aliases)."' OR aliases LIKE '% ".current($aliases)." %') AND domain = '".$data['domain']."' AND id != '".$data['id']."'");
							if (mysql_num_rows($dbp))
								$error[$i++] = $T['err']['domain']['aliases'].current($aliases);

						}
						// not valid
						else
							$error[$i++] = $T['err']['domain']['aliases'].current($aliases);
					} while(next($aliases));

					// Reset $data['aliases'] to a correct value.  The trailing spaces are needed for fast searching (step above)
					// See if it needs an update
					$data['aliases'] = trim(implode(" ",$aliases));
					$data['aliases'] = ereg_replace("[[:space:]]+"," ",$data['aliases']);
				}
			}

			if ($data['aliases'] != $domaindata['aliases'])
				$sql_query .= "aliases=' ".$data['aliases']." ', ";
		}

		// Check Server Sides (PHP, ASP, SSI, SSL, CGI/Perl, Python, etc.)
		// get list from config first.
		if (strstr($cfg['sslang'],",")) $sslang = explode(",",$cfg['sslang']);
		else $sslang[0] = $cfg['sslang'];

		$tmpdata = array();
		if($data['type']=='subdomain' || $data['type']=='pointer')
			$parentss = fetchdata('serverside', 'domain', $domaindata['owner']);
		else
			$parentss = array();

		foreach($sslang as $ss) {
			$ss = trim($ss);
			$domainss = $data['serverside'][$ss];

			//subdomains & pointers will only be n/a if they are forced by their parent(s)
			if($domainss!='on' && !empty($parentss))
				$domainss = 'off';

			if($domainss=='on' || $domainss=='off') {
				if(isset($parentss['serverside'][$ss]) && $parentss['serverside'][$ss]!='on'
				   && $parentss['serverside'][$ss]!= 'off')
					$tmpdata[$ss] = 'na';
				elseif($resellerdata['serverside'][$ss] == 'on')
					$tmpdata[$ss] = $domainss;
				else
					$tmpdata[$ss] = 'na';

			} else
				$tmpdata[$ss] = 'na';
		}

		$data['serverside'] = addslashes(serialize($tmpdata));
		$sql_query .= "serverside='".$data['serverside']."', ";

		/*if ($data['serverside']) {
			$j = 0;
			unset($tmpdata);
			while ($sslang[$j]) {
				$tmp = $data['serverside'][trim($sslang[$j])];
				if (($tmp == "on" OR $tmp == "off") AND $resellerdata['serverside'][trim($sslang[$j])] == "on")
					$tmpdata[trim($sslang[$j])] = $tmp;
				else
					$tmpdata[trim($sslang[$j])] = "na";
				++$j;
			}
			$data['serverside'] = addslashes(serialize($tmpdata));

			// re-serialize domaindata['serverside'] to see if its different than our 'new' serverside
			$tmp = addslashes(serialize($domaindata['serverside']));

			if ($data['serverside'] != $tmp)
				$sql_query .= "serverside='".$data['serverside']."', ";
		}*/

		// Verify Shell
		if (trim($data['shell'])) {
			if ($data['shell'] == "on" OR $data['shell'] == "off" OR $data['shell'] == "ask") {
				if ($resellerdata['shell'] != "on")
					$data['shell'] = "off";
			}
			else $data['shell'] = "off";

			if ($data['shell'] != $domaindata['shell'])
				$sql_query .= "shell='".$data['shell']."', ";
		}

		// HTTP custom check: only for serveradmin+
		if ($data['httpcustom'] AND $userdata['level'] > 1) {
			unset($data['httpcustom']);
		} else {
			$data['httpcustom'] = trim(addslashes($data['httpcustom']));
		}
		if ($data['httpcustom'] != $domaindata['httpcustom']) {
			$sql_query .= "httpcustom='".$data['httpcustom']."', ";
		}

		// IP Restriction Check
		if (isset($data['ip_restrict']) AND $data['ip_restrict'] != $domaindata['ip_restrict']) {
			if (!ereg("^".$data['ip_restrict'],$_SERVER['REMOTE_ADDR']))
				$error[$i++] = $T['err']['domain']['ip_restrict'];
			$sql_query .= "ip_restrict='".$data['ip_restrict']."', ";
		}

		// Check if enough domain, subdomains, pointers, users, hd space are availabe. Validate ['defaultroot'].
		if ($domaindata['type'] == "domain") {
			// users
			if (isset($data['users']) AND $data['users'] != $domaindata['users']) {
				$data['users'] = intval($data['users']);
				$total = $resellerdata['users'];
				$used = $users['users'];
				$current = $domaindata['users'];
				if (($total - $used + $current) < $data['users'] && ($total != -1))
					 $error[$i++] = $T['err']['domain']['no users'].intval($total - $used);
				// Can't have 0 users
				if (!$data['users']) $error[$i++] = $T['err']['domain']['need user'];

				$sql_query .= "users=".$data['users'].", ";
			}

			// subdomains
			if (isset($data['subdomains']) AND $data['subdomains'] != $domaindata['subdomains']) {
				$data['subdomains'] = intval($data['subdomains']);
				$total = $resellerdata['subdomains'];
				$used = $subdomains['subdomains'];
				$current = $domaindata['subdomains'];
				if (($total - $used + $current) < $data['subdomains'] && ($total != -1))
					$error[$i++] = $T['err']['domain']['no subdomains'].intval($total - $used);

				$sql_query .= "subdomains=".$data['subdomains'].", ";
			}

			// pointers
			if (isset($data['pointers']) AND $data['pointers'] != $domaindata['pointers']) {
				$data['pointers'] = intval($data['pointers']);
				$total = $resellerdata['pointers'];
				$used = $pointers['pointers'];
				$current = $domaindata['pointers'];
				if (($total - $used + $current) < $data['pointers'] && ($total != -1))
					$error[$i++] = $T['err']['domain']['no pointers'].intval($total - $used);

				$sql_query .= "pointers='".$data['pointers']."', ";
			}

			// hd space
			if (isset($data['hd']) AND $data['hd'] != $domaindata['hd']) {
				$data['hd'] = intval($data['hd']);
				$total = $resellerdata['hd'];
				$used = $hd['hd'];
				$current = $domaindata['hd'];
				if (($total - $used + $current) < $data['hd'] && ($total != -1))
					$error[$i++] = $T['err']['domain']['no hd'].intval($total - $used);
				// Can't have 0 HD space
				if ($data['hd'] == 0) $error[$i++] = $T['err']['domain']['need hd'].intval($total - $used);

				$sql_query .= "hd='".$data['hd']."', ";
			}

			// databases
			if (isset($data['databases']) AND $data['databases'] != $domaindata['databases']) {
				$data['databases'] = intval($data['databases']);
				$total = $resellerdata['db'];
				$used = $databases['databases'];
				$current = $domaindata['db'];
				if (($total - $used + $current) < $data['databases'] && ($total != -1))
					$error[$i++] = $T['err']['domain']['no databases'].intval($total - $used);

				$sql_query .= "db='".$data['databases']."', ";
			}

			// default user root
			if (isset($data['defaultroot'])) {
				if (!trim($data['defaultroot']))
					$data['defaultroot'] = '/';

				unset($root);
				if (stristr($data['defaultroot'],"%USER%")) {
					$root = explode("%USER%",$data['defaultroot']);
					$defroot = $root[0];
					// make sure the user is created within /www/web or /www/data or /www/users
					if (!strstr($defroot,"/".$data['hostname']."/".$cfg['webname']."/") AND !strstr($defroot,"/".$data['hostname']."/data/") AND !strstr($defroot,"/".$data['hostname']."/users/"))
						$error[$i++] = $T['err']['domain']['invalid user path'];
				} else {
					$defroot = $data['defaultroot'];
				}
				$defroot = ereg_replace("^/","",$defroot);

				// construct real path & verify it
				$dir = $cfg['webdir']."/".$data['id']."/".$defroot;

				if (@!is_dir($dir) && $data['hostname'] == $domaindata['hostname'])
					$error[$i++] = $T['err']['domain']['invalid user path'];
				else {
					if ($root)
						$data['defaultroot'] = $dir."%USER%".$root[1];
					else
						$data['defaultroot'] = $dir;
				}

				if ($data['defaultroot'] != $domaindata['defaultroot'])
					$sql_query .= "defaultroot='".$data['defaultroot']."', ";
			}
		}

		if (trim($data['dnsentry']) AND $data['dnsentry'] != $domaindata['dns']) {
			if ($data['dnsentry'] == "true" OR $data['dnsentry'] == "false")
				$sql_query .= "dns='".$data['dnsentry']."', ";
		}

		// Make sure we are not overwriting something:
		if ($domaindata['action'])
			$tmpaction = $domaindata['action'];
		else
			$tmpaction = 'update';

		$hook_err = Array();
		$hook_err = call_hook('web:domain:'.$action.':check', $data);
		foreach($hook_err as $herr) {
			if ($herr['error'] != '') {
				$error[$i++] = $herr['error'];

			}
			if ($herr['change'] == 'change') {
				$hook_change = true;
			}
		}

		//
		// Update Database

		if ($sql_query == "UPDATE domains SET " && !$hook_change) $error[$i++] = $T['err']['nothing to update'];
		else $sql_query .= "action='$tmpaction' WHERE id = '".$data['id']."'";

		// If any error occured before, return it now
		if (!empty($error)) return $error;
		else {
			mysql_query($sql_query);

			// create md5 signature and insert it.
			$hash = fetchdata("*","domain",$data['id']);
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE domains SET hash='$hash' WHERE id = '".$data['id']."'");
			// update ucount
			mysql_query("UPDATE domains SET ucount = ucount + 1 WHERE domain = '".$data['domain']."'");
			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"domain updated: ".$data['hostname'].".".$data['domain']." [".$data['id']."]",$_SERVER['REMOTE_ADDR']);

			call_hook('web:domain:'.$action, $data);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
	// end 'update'
	///

	//
	// Suspend a domain entry in the database
	elseif ($action == "suspend") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[owner]		*REQUIRED* reseller id
		//
		//
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[id]		domain ID

		// Check update count
		$domain = fetchdata("domain","domain",$data['id']);
		$dbp = mysql_query("SELECT ucount FROM domains WHERE domain='".$domain['domain']."'");
		$ucount = mysql_fetch_array($dbp);
		if ($ucount['ucount'] >= $cfg['ucount'])
			$error[$i++] = sprintf($T['err']['update count'], $cfg['ucount']);

		// Error if the user tries to suspend his own domain
		if ($data['id'] == $userdata['id'])
			$error[$i++] = $T['err']['domain']['suspend myself'];

		// If any error occured before, return it now
		if (!empty($error)) return $error;
		else {
			// Execute the db query
			mysql_query("UPDATE domains SET action='suspend' WHERE id = '".$data['id']."' AND owner='".$data['owner']."'");

			// create md5 signature and insert it.
			$hash = fetchdata("*","domain",$data['id']);
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE domains SET hash='$hash' WHERE id = '".$data['id']."' AND owner='".$data['owner']."'");

			// update ucount
			$domain = fetchdata("domain","domain",$data['id']);
			mysql_query("UPDATE domains SET ucount = ucount + 1 WHERE domain = '".$domain['domain']."'");
			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"domain suspended: ".$data['id'],$_SERVER['REMOTE_ADDR']);

			call_hook('web:domain:'.$action, $data);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
	// end 'suspend'
	///

	//
	// Unsuspend a domain entry in the database
	elseif ($action == "unsuspend") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[owner]		*REQUIRED* reseller id
		//
		//
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[id]		domain ID
		// Execute the db query
		mysql_query("UPDATE domains SET action='unsuspend' WHERE id = '".$data['id']."' AND owner='".$data['owner']."'");

		// create md5 signature and insert it.
		$hash = fetchdata("*","domain",$data['id']);
		$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
		$hash = crypt(md5(serialize($hash)), $cfg['key']);
		mysql_query("UPDATE domains SET hash='$hash' WHERE id = '".$data['id']."' AND owner='".$data['owner']."'");
		// Log it
		webcp_log(2,$userdata['id'],$userdata['username'],"domain unsuspended: ".$data['id'],$_SERVER['REMOTE_ADDR']);

		call_hook('web:domain:'.$action, $data);

		// Tell the system to commit the changes.
		commit("scan");
	}
	// end 'unsuspend'
	///

	//
	// Mark a domain to be removed
	elseif ($action == "remove") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[owner]		*REQUIRED* reseller id
		//
		//
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[id]		domain ID

		// Error if the user tries to remove his own domain
		if ($data['id'] == $userdata['id'])
			$error[$i++] = $T['err']['domain']['remove myself'];

		// If any error occured before, return it now
		if (!empty($error)) return $error;
		else {
			// Execute the db query
			mysql_query("UPDATE domains SET action='remove' WHERE id = '".$data['id']."' AND owner='".$data['owner']."'");

			// create md5 signature and insert it.
			$hash = fetchdata("*","domain",$data['id']);
			$hash['hash'] = $hash['time'] = $hash['ucount'] = '';
			$hash = crypt(md5(serialize($hash)), $cfg['key']);
			mysql_query("UPDATE domains SET hash='$hash' WHERE id = '".$data['id']."' AND owner='".$data['owner']."'");

			// update ucount
			$domain = fetchdata("domain","domain",$data['id']);
			mysql_query("UPDATE domains SET ucount = ucount + 1 WHERE domain = '".$domain['domain']."'");
			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"domain removed: ".$data['id'],$_SERVER['REMOTE_ADDR']);

			call_hook('web:domain:'.$action, $data);

			// Tell the system to commit the changes.
			commit("scan");
		}
	}
	// end 'remove'
	///
}

// Function:	reseller()
// Utility:	Create, Delete, Modify, Suspend, Unsuspend resellers; make sure everything is ok & secure
// Usage:	reseller(ACTION,DATA,RETURN)
// Examples:	reseller("create",$_POST);
//		reseller("delete",$rid);
// Return:	$error		array var or nothing
// Definitions:	ACTION:		create, delete, modify, suspend, unsupend
//		DATA:		reseller id, HTTP_POST_VARS, etc
//		RETURN:		returns reseller ID
function reseller($action,$data,&$return) {
	// Get configurations, userdata, Language file, regex
	GLOBAL $userdata, $cfg, $T, $rx;

	// kill demo users (return error)
	if ($userdata['type'] == "demo") {
		$error[1] = $T['err']['demo user'];
		return $error;
	}

	// Set error 'counter'
	$i = 1;

	// Reset return val
	$return = '';

	//
	// Create a new reseller entry in the database
	if ($action == "create") {
		// Expected Input Data (from POST)
		// ===============================
		// * Optional
		// data[name]		Reseller Name
		// data[email]		Contact E-Mail
		// data[ip]		IP Addresse(s) : single, multiple seperated by space or coma
		// data[domains]	Number of domains.  Can't be 0
		// data[subdomains]	* Number of subdomains.  Can be 0
		// data[pointers]	* Number of domain pointers.  Can be 0
		// data[hd]		HD Quota.  Can't be 0
		// data[users]		Number of users.  Can't be 0
		// data[shell]		on,off
		// data[serverside]	* Serverside http options (php, asp, ssi, ssl, etc)
		// data[databases]	* Number of databases.  Can be 0
		// data[skin]		* User Interface skin. free choice: 'any' or specify a skin name
		//
		// Verify input $data

		// Generate new reseller ID number
		mt_srand((double)microtime()*1000000);
   		do
   			$num = mt_rand(10001,99999);
   		while (fetchdata("id","reseller",$num));

		// Name validity
		if (!eregi($rx['name'],$data['name']))
			$error[$i++] = $T['err']['reseller']['name'];

		// E-Mail validity
		if (!eregi($rx['eml'],$data['email']))
			$error[$i++] = $T['err']['reseller']['email'];

		// Handle IP Addresses
		$ip = split("([[:space:]]+,?|[[:space:]]*,)",$data['ip']);
		if (is_array($ip))
			$data['ip'] = implode(" ",$ip);
		$data['ip'] = ' '.trim($data['ip']).' ';

		// Num Domains
		$data['domains'] = intval($data['domains']);
		if (!$data['domains'])
			$error[$i++] = $T['err']['reseller']['need domains'];

		// Num Users
		$data['users'] = intval($data['users']);
		if (!$data['users'])
			$error[$i++] = $T['err']['reseller']['need users'];

		// Num Domain Pointers
		$data['pointers'] = intval($data['pointers']);

		// Num Subdomains
		$data['subdomains'] = intval($data['subdomains']);

		// Num Databases
		$data['databases'] = intval($data['databases']);

		// HD Quota
		$data['hd'] = intval($data['hd']);
		if (!$data['hd'])
			$error[$i++] = $T['err']['reseller']['need hd'];


		// Check Shell
		if ($data['shell'] != 'on')
			$data['shell'] = 'off';

		// Check Skin
		if (!array_key_exists("skin", $data) OR !file_exists("skin/".$data['skin']))
			$data['skin'] = "any";

		// Check Server Sides (PHP, ASP, SSI, SSL, CGI/Perl, Python, etc.)
		// get list from config first.
		if (strstr($cfg['sslang'],",")) $sslang = explode(",",$cfg['sslang']);
		else $sslang[0] = $cfg['sslang'];

		// Check serverside
		$j = 0;
		unset($tmpdata);
		while (isset($sslang[$j])) {
			if ($data['serverside'][trim($sslang[$j])] == "on")
				$tmpdata[trim($sslang[$j])] = "on";
			else
				$tmpdata[trim($sslang[$j])] = "off";
			++$j;
		}
		$data['serverside'] = addslashes(serialize($tmpdata));

		// Insert into database
		if (!empty($error))
			return $error;
		else {
			mysql_query("INSERT INTO resellers SET id='$num', name='".addslashes($data['name'])."', email='".$data['email']."', ip='".$data['ip']."', domains='".$data['domains']."',
				subdomains='".$data['subdomains']."', pointers='".$data['pointers']."', users='".$data['users']."', hd='".$data['hd']."',
				serverside='".$data['serverside']."', db='".$data['databases']."', shell='".$data['shell']."',
				skin='".$data['skin']."', lastchange=NOW()");

			// Return ID in $return
			$return = $num;

			$data['id'] = $return;
			call_hook('web:reseller:'.$action, $data);

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"reseller created: ".$data['name'],$_SERVER['REMOTE_ADDR']);
		}
	}

	//
	// Update a reseller entry in the database
	elseif ($action == "update") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* reseller id
		//
		//
		// Expected Input Data (from POST)
		// ===============================
		// * All Optional
		// data[name]		Reseller Name
		// data[email]		Contact E-Mail
		// data[ip]		IP Addresse(s) : single, multiple seperated by space or coma
		// data[domains]	Number of domains.  Can't be 0
		// data[subdomains]	Number of subdomains.  Can be 0
		// data[pointers]	Number of domain pointers.  Can be 0
		// data[hd]		HD Quota.  Can't be 0
		// data[users]		Number of users.  Can't be 0
		// data[shell]		on,off
		// data[serverside]	Serverside http options (php, asp, ssi, ssl, etc)
		// data[databases]	Number of databases.  Can be 0
		// data[skin]		User Interface skin. free choice: 'any' or specify a skin name
		// Fetch current resellerdata
		$resellerdata = fetchdata("*","reseller",$data['id']);

		// **** Remove Doubles ($data already in the db) & create SQL query as we check input
		$sql_query = "UPDATE resellers SET ";

		//
		// Verify input $data


		// Name validity
		if (isset($data['name']) AND $data['name'] != $resellerdata['name']) {
			if (!eregi($rx['name'],$data['name']))
				$error[$i++] = $T['err']['reseller']['name'];

			$sql_query .= "name='".addslashes($data['name'])."', ";
		}

		// E-Mail validity
		if (isset($data['email']) AND $data['email'] != $resellerdata['email']) {
			if (!eregi($rx['eml'],$data['email']))
				$error[$i++] = $T['err']['reseller']['email'];

			$sql_query .= "email='".$data['email']."', ";
		}
		// Handle IP Addresses
		if (isset($data['ip']) AND $data['ip'] != $resellerdata['ip']) {
			$ip = split("([[:space:]]+,?|[[:space:]]*,)",$data['ip']);
			if (is_array($ip))
				$data['ip'] = implode(" ",$ip);
			$data['ip'] = ' '.trim($data['ip']).' ';

			$sql_query .= "ip='".$data['ip']."', ";
		}

		// Num Domains
		if (isset($data['domains']) AND $data['domains'] != $resellerdata['domains']) {
			$data['domains'] = intval($data['domains']);
			if (!$data['domains'])
				$error[$i++] = $T['err']['reseller']['need domains'];

			$sql_query .= "domains='".$data['domains']."', ";
		}

		// Num Users
		if (isset($data['users']) AND $data['users'] != $resellerdata['users']) {
			$data['users'] = intval($data['users']);
			if (!$data['users'])
				$error[$i++] = $T['err']['reseller']['need users'];

			$sql_query .= "users='".$data['users']."', ";
		}

		// Num Domain Pointers
		if (isset($data['pointers']) AND $data['pointers'] != $resellerdata['pointers']) {
			$data['pointers'] = intval($data['pointers']);
			$sql_query .= "pointers='".$data['pointers']."', ";
		}

		// Num Subdomains
		if (isset($data['subdomains']) AND $data['subdomains'] != $resellerdata['subdomains']) {
			$data['subdomains'] = intval($data['subdomains']);
			$sql_query .= "subdomains='".$data['subdomains']."', ";
		}

		// Num Databases
		if (isset($data['databases']) AND $data['databases'] != $resellerdata['db']) {
			$data['databases'] = intval($data['databases']);
			$sql_query .= "db='".$data['databases']."', ";
		}

		// HD Quota
		if (isset($data['hd']) AND $data['hd'] != $resellerdata['hd']) {
			$data['hd'] = intval($data['hd']);
			if (!$data['hd'])
				$error[$i++] = $T['err']['reseller']['need hd'];

			$sql_query .= "hd='".$data['hd']."', ";
		}

		// Check Shell
		if (isset($data['shell']) AND $data['shell'] != $resellerdata['shell']) {
			if ($data['shell'] != 'on')
				$data['shell'] = 'off';

			$sql_query .= "shell='".$data['shell']."', ";
		}

		// Check Skin
		if (isset($data['skin']) AND $data['skin'] != $resellerdata['skin']) {
			if (!trim($data['skin']) OR !file_exists("skin/".$data['skin']))
				$data['skin'] = "any";

			$sql_query .= "skin='".$data['skin']."', ";
		}

		// Check Server Sides (PHP, ASP, SSI, SSL, CGI/Perl, Python, etc.)
		// get list from config first.
		if (strstr($cfg['sslang'],",")) $sslang = explode(",",$cfg['sslang']);
		else $sslang[0] = $cfg['sslang'];

		// Check serverside
		if ($data['serverside']) {
			$j = 0;
			unset($tmpdata);
			while ($sslang[$j]) {
				if ($data['serverside'][trim($sslang[$j])] == "on")
					$tmpdata[trim($sslang[$j])] = "on";
				else
					$tmpdata[trim($sslang[$j])] = "off";
				++$j;
			}
			$data['serverside'] = addslashes(serialize($tmpdata));

			// re-serialize domaindata['serverside'] to see if its different than our 'new' serverside
			$tmp = addslashes(serialize($resellerdata['serverside']));

			if ($data['serverside'] != $tmp)
				$sql_query .= "serverside='".$data['serverside']."', ";
		}

		$retval = Array();
		$retval = call_hook('web:reseller:'.$action.':check', $data);

		// Check if there is anything to update
		if ($sql_query == "UPDATE resellers SET " && !in_array('change', $retval))
			$error[$i++] = $T['err']['nothing to update'];
		else
			$sql_query .= "lastchange=NOW() WHERE id = '".$data['id']."'";

		// Insert into database
		if (!empty($error))
			return $error;
		else {
			mysql_query($sql_query);

			call_hook('web:reseller:'.$action, $data);

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"reseller updated: ".$data['name'],$_SERVER['REMOTE_ADDR']);
		}
	}

	//
	// Suspend a reseller (suspend its domains which in turn suspend their users)
	elseif ($action == "suspend") {
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[id]		reseller ID
		//

		// Error if the user tries to suspend his own reseller
		if ($data['id'] == substr($userdata['id'], 0, 5))
			$error[$i++] = $T['err']['reseller']['suspend myself'];

		// If any error occured before, return it now
		if (!empty($error)) return $error;
		else {
			// fetch domain IDs under this reseller and suspend them
			$dbp = mysql_query("SELECT id,owner FROM domains WHERE owner = '".$data['id']."'");
			while ($ddata = mysql_fetch_array($dbp))
				domain("suspend",$ddata,$return);

			call_hook('web:reseller:'.$action, $data);

			// Insert into database
			mysql_query("UPDATE resellers SET hold='true' WHERE id = '".$data['id']."'");

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"reseller suspended: ".$data['id'],$_SERVER['REMOTE_ADDR']);
		}
	}


	//
	// Unsuspend a reseller (unsuspend its domains which in turn unsuspend their users)
	elseif ($action == "unsuspend") {
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[id]		reseller ID
		//

		// fetch domain IDs under this reseller and suspend them
		$dbp = mysql_query("SELECT id,owner FROM domains WHERE owner = '".$data['id']."'");
		while ($ddata = mysql_fetch_array($dbp))
			domain("unsuspend",$ddata,$return);

		call_hook('web:reseller:'.$action, $data);

		// Insert into database
		mysql_query("UPDATE resellers SET hold='false' WHERE id = '".$data['id']."'");
		// Log it
		webcp_log(2,$userdata['id'],$userdata['username'],"reseller reactivated: ".$data['id'],$_SERVER['REMOTE_ADDR']);
	}

	//
	// Remove a reseller (remove its domains which in turn remove their users)
	elseif ($action == "remove") {
		// Expected Input Data (from POST/GET)
		// ===============================
		//
		// data[id]		reseller ID
		//

		// Error if the user tries to suspend his own reseller
		if ($data['id'] == substr($userdata['id'], 0, 5))
			$error[$i++] = $T['err']['reseller']['remove myself'];

		// If any error occured before, return it now
		if (!empty($error)) return $error;
		else {
			// fetch domain IDs under this reseller and set them to be removed
			$dbp = mysql_query("SELECT id,owner FROM domains WHERE owner = '".$data['id']."'");
			while ($ddata = mysql_fetch_array($dbp))
				domain("remove",$ddata,$return);

			call_hook('web:reseller:'.$action, $data);

			// Remove from database
			mysql_query("DELETE FROM resellers WHERE id = '".$data['id']."'");

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"reseller removed: ".$data['id'],$_SERVER['REMOTE_ADDR']);
		}
	}
}

// Function:	database()
// Utility:	Create, Delete, Modify, Suspend, Unsuspend databases; make sure everything is ok & secure
// Usage:	database(ACTION,DATA)
// Examples:	database("create",$_POST);
//		database("delete",$rid);
// Return:	$error		array var or nothing
// Definitions:	ACTION:		create, delete, modify, suspend, unsupend
//		DATA:		database name, HTTP_POST_VARS, etc
function database($action,$data,&$return) {
	// Get configurations, userdata, Language file, regex
	GLOBAL $userdata, $cfg, $T, $rx;

	// kill demo users (return error)
	if ($userdata['type'] == "demo") {
		$error[1] = $T['err']['demo user'];
		return $error;
	}

	// Set error 'counter'
	$i = 1;

	// Reset return val
	$return = '';

	//
	// Create a new database entry in the database
	if ($action == "create") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain id
		// data[uid]	*REQUIRED* username
		//
		// Expected Input Data (from POST)
		// ===============================
		// * Optional
		// data[name]		Database Name
		// data[username]	Database username
		// data[password]	Database password
		// data[access]		Database Access: localhost|any
		// data[type]		Database Type: mysql|postgresql

		// Check for the number of databases in use
		$domaindata = fetchdata("db","domain",$data['id']);
		$databases = fetchdata("db","total",$data['id']);

		// Verify the user belongs to the current domain
		$dbp = mysql_query('SELECT id, user FROM properties WHERE '
			.'name = "mysql user" AND value = "'.$data['username'].'" LIMIT 1');
		$tmp = mysql_fetch_assoc($dbp);

		if (mysql_num_rows($dbp)!=0 && ($tmp['id'] != $data['id'] || $tmp['user'] != $data['uid'])) {
			$error[$i++] = $T['err']['db']['username'].'--';
		}

		// Deal with MySQL or PostgreSQL only
		if ($data['type'] != 'mysql' AND $data['type'] != 'postgresql')
			$error[$i++] = $T['err']['db']['invalid type'];

		// Verify username validity
		if (!eregi($rx['user'],$data['username']) OR strlen($data['username']) > 16)
			$error[$i++] = $T['err']['db']['username'];
		// Verify password
		if (!eregi($rx['pass'],$data['password'])/* AND !$userset*/)
			$error[$i++] = $T['err']['db']['password'];

		// Check for weak password
		if ($cfg['strong_passwords']) {
			if (!password_check($data['password'])) {
				$error[$i++] = $T['err']['db']['weakpassword'];
			}
		}

		if(strlen($data['name'])>64) {
			$error[$i++] = $T['err']['db']['invalid db'];
		}

		// Check for if there are free databases left:
		$total = $domaindata['db'];
		$used = $databases['db'];
		if (($total - $used) < 1 && ($total != -1)) $error[$i++] = $T['err']['db']['no db'];

		// Check for MySQL database name availability
		if ($data['type'] == 'mysql') {
			$dbp = mysql_query('SHOW DATABASES LIKE "'.$data['name'].'"');
			if (mysql_num_rows($dbp)!=0) {
				$error[$i++] = $T['err']['db']['name taken'];
			}

			// check if db user already exist
			mysql_select_db('mysql');
			$dbp = mysql_query("SELECT User FROM user WHERE User='".$data['username']."'");
			if (mysql_num_rows($dbp))
				$userset = true;
			else
				$userset = false;

			mysql_select_db($cfg['dbname']);
		}

		// Deal with PostgreSQL
		elseif ($data['type'] == 'postgresql') {
			// Name is free?
			$pgstr = "host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$data['name'];
			if ($psql = @pg_connect($pgstr)) {
				$error[$i++] = $T['err']['db']['name taken'];
			}
			@pg_close($psql);

			// check if db user already exist
			$psql = pg_connect("host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$cfg['pgsql_db']);
			if (!@pg_query($psql,"ALTER USER ".$data['username']))
				$userset = false;
			else
				$userset = true;
			pg_close($psql);
		}


		// If any error occured before, return it now
		if (!empty($error)) {
			return $error;
		} else {
			set_property('mysql user', $data['username'], $data['id'], $data['uid']);

			if ($data['type'] == 'mysql') {
				// Create database (and user if appropriate)
				if (!mysql_query("CREATE DATABASE `".$data['name']."`")) {
					$error[$i++] = $T['err']['db']['no create'].' '.mysql_error();
				}
				mysql_select_db('mysql');
				if (!$userset) {
					$SQL = "INSERT INTO user SET Host='%', User='".$data['username']."', password=PASSWORD('".$data['password']."')";
					if ($cfg['mysql_resource_limits']) {
						$SQL .= ", max_questions=".$cfg['mysql_qph'].", max_updates=".$cfg['mysql_uph'].", max_connections=".$cfg['mysql_cph'];
					}
					mysql_query($SQL);
					$SQL = "INSERT INTO user SET Host='localhost', User='".$data['username']."', password=PASSWORD('".$data['password']."')";
					if ($cfg['mysql_resource_limits']) {
						$SQL .= ", max_questions=".$cfg['mysql_qph'].", max_updates=".$cfg['mysql_uph'].", max_connections=".$cfg['mysql_cph'];
					}
					mysql_query($SQL);
				}
				mysql_query("INSERT INTO db SET Host='".$data['access']."', Db='".$data['name']."', User='".$data['username']."', Select_priv='Y',
						Insert_priv='Y', Update_priv='Y', Delete_priv='Y', Create_priv='Y' ,Drop_priv='Y', Grant_priv='N',
						References_priv='Y', Index_priv='Y', Alter_priv='Y'");
				mysql_query("FLUSH PRIVILEGES");
				mysql_select_db($cfg['dbname']);
			}
			elseif ($data['type'] == 'postgresql') {
				// Create database (and user if appropriate)
				$pgstr = "host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$cfg['pgsql_db'];
				if ($psql = pg_connect($pgstr)) {
					if (!$userset) {
						pg_query($psql,"CREATE USER \"".$data['username']."\" WITH ENCRYPTED PASSWORD '".$data['password']."' CREATEDB");
					}else {
						pg_query($psql,"ALTER USER \"".$data['username']."\" CREATEDB");
					}
				}
				pg_close($psql);
				if ($psql = pg_connect("host=".$cfg['pgsql_host']." user=".$data['username']." password=".$data['password']." dbname=".$cfg['pgsql_db'])) {
					if (pg_query($psql,"CREATE DATABASE \"".$data['name']."\"")) {
					}
					pg_close($psql);
				}
				$psql = pg_connect("host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$cfg['pgsql_db']);
				pg_query($psql,"ALTER USER \"".$data['username']."\" NOCREATEDB");
				pg_close($psql);

			}

			// Log it
			webcp_log(2,$userdata['id'],$userdata['username'],"database created: ".$data['name'],$_SERVER['REMOTE_ADDR']);
		}
	}

	//
	// Modify a database
	elseif ($action == "updatemysql") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain id
		// data[type]	*REQUIRED* Database Type (mysql|postgresql)
		//
		// Expected Input Data (from POST)
		// ===============================
		// ** Both groups are optional
		// data[name]		Database Name
		// data[access]		Database Access: localhost|any
		if ($data['type'] == 'mysql') {
			if ($data['name']) {
				// Update host if appropriate
				if ($cfg['mysql_access_define'] && $data['access'] != '') {
					$SQL = "UPDATE db SET Host='".$data['access']."' WHERE Db='".$data['name']."'";
					$SQL2 = "UPDATE user SET Host='".$data['access']."' WHERE user='".$data['user']."'";
					mysql_select_db('mysql');
					mysql_query($SQL);
					mysql_query($SQL2);
					mysql_query("FLUSH PRIVILEGES");
					mysql_select_db($cfg['dbname']);
					// Log it
					webcp_log(2,$userdata['id'],$userdata['username'],"database updated: ".$data['name']." (host)",$_SERVER['REMOTE_ADDR']);
				}

				if ($cfg['mysql_password_define'] && $data['password'] != '') {
					// Verify password
					if (!eregi($rx['pass'],$data['password']))
						$error[$i++] = $T['err']['db']['password'];

					// Check for weak password
					if ($cfg['strong_passwords']) {
						if (!password_check($data['password'])) {
							$error[$i++] = $T['err']['db']['weakpassword'];
						}
					}
					if (is_array($error)) return $error;
					else {
						$SQL2 = "UPDATE user SET password=PASSWORD('".$data['password']."') WHERE user='".$data['user']."'";
					}
					mysql_select_db('mysql');
					mysql_query($SQL2);
					mysql_query("FLUSH PRIVILEGES");
					mysql_select_db($cfg['dbname']);
					// Log it
					webcp_log(2,$userdata['id'],$userdata['username'],"database user updated: ".$data['user']." (password)",$_SERVER['REMOTE_ADDR']);
				}
			}
		}
	}

	//
	// Suspend a database
	elseif ($action == "suspend") {
		if ($data['type'] == 'mysql') {
			mysql_select_db("mysql");

			//Verify the database belongs to this domain
			$dbp = mysql_query("SELECT User FROM db WHERE Db = '".$data['name']."'");
			$user = mysql_fetch_array($dbp);

			mysql_select_db($cfg['dbname']);

			$dbp = mysql_query('SELECT id FROM properties WHERE '
				.'name = "mysql user" AND value = "'.$user['User'].'" LIMIT 1');
			$tmp = mysql_fetch_assoc($dbp);

			if (mysql_num_rows($dbp)==0 || $tmp['id'] != $data['id']) {
				$error[] = $T['err']['db']['name'];
				return $error;
			}

			mysql_select_db("mysql");

			$SQL = "SELECT host FROM db WHERE Db = '".$data['name']."'";
			$res = mysql_query($SQL);
			$row = mysql_fetch_array($res);
			$SQL = "UPDATE db SET host = 'suspended|".$row['host']."' WHERE Db = '".$data['name']."'";
			mysql_query($SQL);
			mysql_query("FLUSH PRIVILEGES");
			mysql_select_db($cfg['dbname']);
		}
	}

	//
	// Unsuspend a database
	elseif ($action == "unsuspend") {
		if ($data['type'] == 'mysql') {
			mysql_select_db("mysql");

			//Verify the database belongs to this domain
			$dbp = mysql_query("SELECT User FROM db WHERE Db = '".$data['name']."'");
			$user = mysql_fetch_array($dbp);

			mysql_select_db($cfg['dbname']);

			$dbp = mysql_query('SELECT id FROM properties WHERE '
				.'name = "mysql user" AND value = "'.$user['User'].'" LIMIT 1');
			$tmp = mysql_fetch_assoc($dbp);

			if (mysql_num_rows($dbp)==0 || $tmp['id'] != $data['id']) {
				$error[] = $T['err']['db']['name'];
				return $error;
			}

			mysql_select_db("mysql");

			$SQL = "SELECT host FROM db WHERE Db = '".$data['name']."'";
			$res = mysql_query($SQL);
			$row = mysql_fetch_array($res);
			$SQL = "UPDATE db SET host = '".str_replace("suspended|","",$row['host'])."' WHERE Db = '".$data['name']."'";
			mysql_query($SQL);
			mysql_query("FLUSH PRIVILEGES");
			mysql_select_db($cfg['dbname']);
		}
	}

	//
	// Remove a database
	elseif ($action == "remove") {
		// Expected Input Data (assumed SAFE, should be hardcoded)
		// ===============================
		//
		// data[id]		*REQUIRED* domain id
		//
		// Expected Input Data (from POST)
		// ===============================
		// data[type]		Database Type (mysql|postgresql)
		// data[name]		Database Name
		if ($data['type'] == 'mysql') {
			// Create database (and user if appropriate)
			mysql_select_db("mysql");
			$dbp = mysql_query("SELECT User FROM db WHERE Db = '".$data['name']."'");
			$user = mysql_fetch_array($dbp);

			mysql_select_db($cfg['dbname']);

			//Verify the database belongs to this domain
			$dbp = mysql_query('SELECT id FROM properties WHERE '
				.'name = "mysql user" AND value = "'.$user['User'].'" LIMIT 1');
			$tmp = mysql_fetch_assoc($dbp);

			if (mysql_num_rows($dbp)==0 || $tmp['id'] != $data['id']) {
				$error[] = $T['err']['db']['name'];
				return $error;
			}

			mysql_select_db("mysql");

			mysql_query("DROP DATABASE IF EXISTS `".$data['name']."`");

			mysql_query("DELETE FROM db WHERE Db='".$data['name']."'");
			$dbp = mysql_query("SELECT Db FROM db WHERE User = '".$user['User']."'");
			if (!mysql_num_rows($dbp)) {
				mysql_query("DELETE FROM user WHERE User='".$user['User']."'");
			}
			mysql_query("FLUSH PRIVILEGES");
			mysql_select_db($cfg['dbname']);
		}
		elseif ($data['type'] == 'postgresql') {
			if ($psql = pg_connect("host=".$cfg['pgsql_host']." user=".$cfg['pgsql_user']." password=".$cfg['pgsql_pass']." dbname=".$cfg['pgsql_db'])) {
				if (!pg_query($psql,'DROP DATABASE "'.$data['name'].'"')) {
					echo pg_last_error();
				}
			}
			pg_close($psql);
		}
	}
}

function array2xml($val, $key, $level) {
	//$key = str_replace('_', '-', $key);
	if(is_array($val)) {
		if(is_assoc($val)) {
			echo str_repeat('  ', $level).'<'.$key.'>'."\n";
			array_walk($val, 'array2xml', $level+1);
			echo str_repeat('  ', $level).'</'.$key.'>'."\n";
		} else {
			foreach($val as $v) {
				array2xml($v, $key, $level);
				//echo str_repeat('  ', $level).'<'.$key.'>'.$v.'</'$key.'>'."\n";
			}
		}
	} else {
		echo str_repeat('  ', $level).'<'.$key.'>'.$val.'</'.$key.'>'."\n";
	}
}

function load_data_vars(&$data, $names) {
	foreach($names as $name) {
		$data[$name] = load_input_vars($name);
	}
}

function is_assoc($var) {
   return is_array($var) && array_keys($var) !== range(0, count($var)-1);
}



function array_concat(&$work, &$add, $overwrite=true) {
	foreach($add as $k => $v) {
		if(isset($work[$k])) {
			if(is_array($work[$k]) && is_array($v)) {
				array_concat($work[$k], $v, $overwrite);
			} elseif($overwrite) {
				$work[$k] = $v;
			}
		} else {
			$work[$k] = $v;
		}
	}
}

//include() with caching
function load_cached_file($file, $var) {
	//convert file.ext to file.cache.ext
	$ext_pos = strrpos($file, '.');
	if($ext_pos===false)
		$cache_file = $file.'.cache';
	else
		$cache_file = substr($file, 0, $ext_pos).'.cache'.substr($file, $ext_pos);

	if(!file_exists($cache_file) || filemtime($file) > filemtime($cache_file) || !is_readable($cache_file)) {
		//
		include($file);
		@file_put_contents($cache_file, '<?php return; ?>'.serialize($$var));
	} else {
		$$var = unserialize(substr(file_get_contents($cache_file), 16));
		//include($cache_file);
	}

	if(isset($GLOBALS[$var]) && is_array($GLOBALS[$var]))
		array_concat($GLOBALS[$var], $$var, true);
		//$GLOBALS[$var] = array_merge_recursive($GLOBALS[$var], $$var);
	else
		$GLOBALS[$var] = $$var;
}

// import sql dump/execute multiple queries
// This code is quite naive and not very robust, but should work for all web-cp sql dumps
function import_sql_dump($sql) {
	$sql = str_replace("\r\n", "\n", $sql);
	$sql = str_replace("\r", "\n", $sql);
	$lines = explode("\n", $sql);
	$queries = array();
	$query = '';
	foreach($lines as $line) {
		if(empty($line) || $line{0}=='#' || substr($line, 0, 2)=='--' || substr($line, 0, 2)=='/*')
			continue;

		$query .= $line;
		if(substr($line, -1)==';') {
			$queries[] = substr($query, 0, -1);
			$query = '';
		}
	}
	if(!empty($query)) {
		$queries[] = $query;
		$query = '';
	}

	$errors = array();
	foreach($queries as $query) {
		if(!mysql_query($query))
			$errors[] = mysql_error();
	}

	return $errors;
}

//return a timestamp in GMT time
function gmtime($time=null) {
	if($time===null)
		$time = time();
	return mktime(gmdate('G', $time), gmdate('i', $time), gmdate('s', $time), gmdate('m', $time), gmdate('d', $time), gmdate('Y', $time));
}

class techticket {
	var $name;
	var $email;
	var $id;
	var $ticketid;
	var $subject;
	var $body;
	var $domain;
	var $domainID;
	var $ipaddress;
	var $creationdate;
	var $submissiondate;
	var $escalation;
	var $priority;
	var $status;
	var $category;
	var $age;
	var $ageDays;
	var $ageHours;
	var $ageMinutes;
	var $ageSeconds;
	var $size;
	var $assignUsername;
	var $assignEmail;
	var $assignName;

	function openTicket($id) {
		$SQL = "SELECT firstname, lastname, ticketid, subject, body, domain, email, ipaddress, creationdate, submissiondate, escalation, priority, status, category FROM (((helpdesk_tickets inner join helpdesk_statuses ON helpdesk_tickets.statusid = helpdesk_statuses.id) inner join helpdesk_ticket_cat ON helpdesk_tickets.categoryid = helpdesk_ticket_cat.id) inner join helpdesk_ticket_escalation ON helpdesk_tickets.escalationid = helpdesk_ticket_escalation.id) inner join helpdesk_ticket_priorities ON helpdesk_tickets.priorityid = helpdesk_ticket_priorities.id WHERE helpdesk_tickets.id = $id";
		$res = mysql_query($SQL);
		$row = mysql_fetch_array($res);
		$this->name[] = $row["firstname"] . " " . $row["lastname"];
		$this->email[] = $row["email"];
		$this->id[] = $id;
		$this->ticketid[] = $row["ticketid"];
		$this->subject[] = $row["subject"];
		$this->body[] = $row["body"];
		$this->domain[] = $row["domain"];
		$this->ipaddress[] = $row["ipaddress"];
		$this->creationdate[] = $row["creationdate"];
		$this->shortcreationdate[] = date("n/j g:ia", strtotime($row["creationdate"]));
		$this->submissiondate[] = $row["submissiondate"];
		$this->shortsubmissiondate[] = date("n/j g:ia", strtotime($row["submissiondate"]));
		$this->escalation[] = $row["escalation"];
		$this->priority[] = $row["priority"];
		$this->status[] = $row["status"];
		$this->category = $row["category"];
		$this->assignUsername[] = "";
		$this->assignEmail[] = "";
		$this->assignName[] = "";

		$SQL = "SELECT assigneduser, helpdesk_ticket_followups.id, firstname, lastname, ticketid, subject, body, helpdesk_ticket_followups.domain as domain, helpdesk_ticket_followups.email as email, ipaddress, creationdate, submissiondate, escalation, helpdesk_ticket_priorities.priority as priority, status, users.username as assignUsername, concat(users.username, domains.domain) as assignEmail, users.name as assignName FROM ((((helpdesk_ticket_followups inner join helpdesk_statuses ON helpdesk_ticket_followups.statusid = helpdesk_statuses.id) inner join helpdesk_ticket_escalation ON helpdesk_ticket_followups.escalationid = helpdesk_ticket_escalation.id) inner join helpdesk_ticket_priorities ON helpdesk_ticket_followups.priorityid = helpdesk_ticket_priorities.id) left join users ON helpdesk_ticket_followups.assigneduser = users.username) left join domains ON users.id = domains.id  WHERE helpdesk_ticket_followups.ticketid = $id ORDER BY creationdate asc";
		$res = mysql_query($SQL);
		for ($i=0; $row = mysql_fetch_array($res); $i++) {
			$this->name[] = $row["firstname"] . " " . $row["lastname"];
			$this->email[] = $row["email"];
			$this->id[] = $row["id"];
			$this->ticketid[] = $row["ticketid"];
			$this->subject[] = $row["subject"];
			$this->body[] = $row["body"];
			$this->domain[] = $row["domain"];
			$this->ipaddress[] = $row["ipaddress"];
			$this->creationdate[] = $row["creationdate"];
			$this->shortcreationdate[] = date("n/j g:ia", strtotime($row["creationdate"]));
			$this->submissiondate[] = $row["submissiondate"];
			$this->shortsubmissiondate[] = date("n/j g:ia", strtotime($row["submissiondate"]));
			$this->escalation[] = $row["escalation"];
			$this->priority[] = $row["priority"];
			$this->status[] = $row["status"];
			$this->assignUsername[] = $row["assignUsername"];
			$this->assignEmail[] = $row["assignEmail"];
			$this->assignName[] = $row["assignName"];
		}

		$this->getAge(0);

		$this->size = sizeOf($this->id);

		$this->checkDomainID($this->size - 1);
	}
	function checkDomainID($i) {
		$SQL = "SELECT id FROM domains WHERE domain = '".$this->domain[$i]."' ORDER BY type='domain', type='pointer', type='subdomain'";
		$domainres = mysql_query($SQL);
		if ($row = mysql_fetch_array($domainres)) {
			$this->domainID[$i] = $row['id'];
		}
	}

	function getAge($i) {
		$seconds = time() - strtotime($this->creationdate[$i]);
		if (($seconds / 86400) >= 1) {
		 	$days = intval($seconds / 86400);
		 	$seconds = $seconds - ($days * 86400);
		 	$this->age[$i] .= $days."D ";
		}
		if (($seconds / 3600) >= 1) {
		 	$hours = intval($seconds / 3600);
		 	$seconds = $seconds - ($hours * 3600);
		 	$this->age[$i] .= $hours.":";
		}
		if (($seconds / 60) >= 1) {
		 	$minutes = intval($seconds / 60);
		 	$seconds = $seconds - ($minutes * 60);
		 	$this->age[$i] .= (($minutes < 10 && $hours != "") ? "0".$minutes : $minutes).":";
		} elseif($hours != "") {
			$this->age[$i] .= "00:";
		}
		$this->age[$i] .= (($seconds < 10 && $minutes != "") ? "0".$seconds : $seconds);

		$this->ageDays[$i] = $days;
		$this->ageHours[$i] = $hours;
		$this->ageMinutes[$i] = $minutes;
		$this->ageSeconds[$i] = $seconds;
	}

	function closeTicket() {
		unset($this->name);
		unset($this->email);
		unset($this->id);
		unset($this->ticketid);
		unset($this->subject);
		unset($this->body);
		unset($this->domain);
		unset($this->ipaddress);
		unset($this->creationdate);
		unset($this->shortcreationdate);
		unset($this->submissiondate);
		unset($this->shortsubmissiondate);
		unset($this->escalation);
		unset($this->priority);
		unset($this->status);
		unset($this->category);
	}
}

// The following functions are here to support using versions of PHP prior to 5
// They are taken from the upgrade library available at http://upgradephp.berlios.de

#-- file related constants
if (!defined("FILE_APPEND")) {
   define("FILE_USE_INCLUDE_PATH", 1);
   define("FILE_IGNORE_NEW_LINES", 2);
   define("FILE_SKIP_EMPTY_LINES", 4);
   define("FILE_APPEND", 8);
   define("FILE_NO_DEFAULT_CONTEXT", 16);
}

#-- simplified file read-at-once function
if (!function_exists("file_get_contents")) {
   function file_get_contents($filename, $use_include_path=1) {

      #-- open file, let fopen() report error
      $f = fopen($filename, "rb", $use_include_path);
      if (!$f) { return; }

      #-- read max 2MB
      $content = fread($f, 1<<21);
      fclose($f);
      return($content);
   }
}

#-- write-at-once file access
if (!function_exists("file_put_contents")) {
   function file_put_contents($filename, $data, $flags=0, $resource=NULL) {

      #-- prepare
      $mode = ($flags & FILE_APPEND ? "a" : "w" ) ."b";
      $incl = $flags & FILE_USE_INCLUDE_PATH;
      $length = strlen($data);

      #-- open for writing
      $f = fopen($filename, $mode, $incl);
      if ($f) {
         $written = fwrite($f, $data);
         fclose($f);

         #-- only report success, if completely saved
         return($length == $written);
      }
   }
}


#-- case-insensitive string search function,
#   - finds position of first occourence of a string c-i
#   - parameters identical to strpos()
if (!function_exists("stripos")) {
   function stripos($haystack, $needle, $offset=NULL) {

      #-- simply lowercase args
      $haystack = strtolower($haystack);
      $needle = strtolower($needle);

      #-- search
      $pos = strpos($haystack, $needle, $offset);
      return($pos);
   }
}

#-- check for key intersections
if (!function_exists('array_intersect_key')) {
function array_intersect_key($arr1, $arr2) {
   $res = array();
   foreach($arr1 as $key=>$value) {
       $push = true;
       for ($i = 1; $i < func_num_args(); $i++) {
           $actArray = func_get_arg($i);
           if (gettype($actArray) != 'array') return false;
           if (!array_key_exists($key, $actArray)) $push = false;
       }
       if ($push) $res[$key] = $arr1[$key];
   }
   return $res;
}
}

?>
